GMS Linux: start?

This commit is contained in:
2025-12-30 01:20:20 +00:00
commit ac241a9148
48 changed files with 2028 additions and 0 deletions
+15
View File
@@ -0,0 +1,15 @@
TARGET = argdump
SRCS = argdump.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)
+16
View File
@@ -0,0 +1,16 @@
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
printf("----------------------------------------\n");
printf("Executable: '%s'\n", argv[0]);
printf("Total Args: %d\n", argc);
printf("----------------------------------------\n");
for (int i = 0; i < argc; i++) {
printf("argv[%d] (len=%2d): [%s]\n", i, (int)strlen(argv[i]), argv[i]);
}
printf("----------------------------------------\n");
return 0;
}
+15
View File
@@ -0,0 +1,15 @@
TARGET = bracket
SRCS = bracket.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)
+108
View File
@@ -0,0 +1,108 @@
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#define MAX_ITEMS 1024
#define ITEMS_PER_WORD 16
typedef struct {
uint32_t data[MAX_ITEMS / ITEMS_PER_WORD];
int top;
} BitStack;
void init_stack(BitStack *s) {
s->top = 0;
memset(s->data, 0, sizeof(s->data));
}
int encode(char c) {
switch(c) {
case '(': return 0;
case '{': return 1;
case '[': return 2;
default: return 3;
}
}
char decode(int code) {
switch(code) {
case 0: return '(';
case 1: return '{';
case 2: return '[';
default: return '?';
}
}
bool push(BitStack *s, char c) {
if (s->top >= MAX_ITEMS) return false;
int code = encode(c);
int word_idx = s->top / ITEMS_PER_WORD;
int bit_offset = (s->top % ITEMS_PER_WORD) * 2;
s->data[word_idx] &= ~((uint32_t)0x3 << bit_offset);
s->data[word_idx] |= ((uint32_t)code << bit_offset);
s->top++;
return true;
}
char pop(BitStack *s) {
if (s->top <= 0) return '\0';
s->top--;
int word_idx = s->top / ITEMS_PER_WORD;
int bit_offset = (s->top % ITEMS_PER_WORD) * 2;
int code = (s->data[word_idx] >> bit_offset) & 0x3;
return decode(code);
}
bool is_empty(BitStack *s) {
return s->top == 0;
}
bool check_bracket(char *str) {
BitStack s;
init_stack(&s);
int len = strlen(str);
for (int i = 0; i < len; i++) {
char ch = str[i];
if (ch == '(' || ch == '{' || ch == '[') {
if (!push(&s, ch)) {
printf("Error: Stack Overflow\n");
return false;
}
}
else if (ch == ')' || ch == '}' || ch == ']') {
if (is_empty(&s)) return false;
char open_ch = pop(&s);
if (ch == ')' && open_ch != '(') return false;
if (ch == '}' && open_ch != '{') return false;
if (ch == ']' && open_ch != '[') return false;
}
}
return is_empty(&s);
}
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: bracket <string>\n");
return 1;
}
if (check_bracket(argv[1])) {
printf("Valid\n");
return 0;
} else {
printf("Invalid\n");
return 1;
}
}
+15
View File
@@ -0,0 +1,15 @@
TARGET = cat
SRCS = cat.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)
+30
View File
@@ -0,0 +1,30 @@
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
char buf[1024];
int n;
int fd;
if (argc == 1) {
while ((n = read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
write(STDOUT_FILENO, buf, n);
}
return 0;
}
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);
}
return 0;
}
+15
View File
@@ -0,0 +1,15 @@
TARGET = cp
SRCS = cp.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)
+42
View File
@@ -0,0 +1,42 @@
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#define BUF_SIZE 4096
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("Usage: cp <source> <dest>\n");
return 1;
}
int src_fd = open(argv[1], O_RDONLY);
if (src_fd < 0) {
perror("cp: source open error");
return 1;
}
// dest 파일 생성 (이미 있으면 덮어쓰기)
int dest_fd = open(argv[2], O_CREAT | O_TRUNC | O_WRONLY, 0644);
if (dest_fd < 0) {
perror("cp: dest open error");
close(src_fd);
return 1;
}
char buf[BUF_SIZE];
int n;
// EOF(0)가 될 때까지 읽어서 씀
while ((n = read(src_fd, buf, BUF_SIZE)) > 0) {
if (write(dest_fd, buf, n) != n) {
perror("cp: write error");
break;
}
}
close(src_fd);
close(dest_fd);
return 0;
}
+15
View File
@@ -0,0 +1,15 @@
TARGET = debug
SRCS = debug.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)
+59
View File
@@ -0,0 +1,59 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/time.h>
int main(int argc, char *argv[]) {
if (argc < 2) {
printf("Usage: debug <command> [args...]\n");
return 1;
}
struct timeval start, end;
gettimeofday(&start, NULL);
pid_t pid = fork();
if (pid < 0) {
perror("debug: fork failed");
return 1;
}
if (pid == 0) {
execvp(argv[1], &argv[1]);
perror("debug: exec failed");
exit(127);
}
else {
int status;
waitpid(pid, &status, 0);
gettimeofday(&end, NULL);
long seconds = end.tv_sec - start.tv_sec;
long micros = end.tv_usec - start.tv_usec;
if (micros < 0) {
seconds -= 1;
micros += 1000000;
}
double elapsed = seconds + micros / 1000000.0;
printf("\n\033[1;33m[Debug Report]\033[0m\n");
printf("Target : %s\n", argv[1]);
printf("PID : %d\n", pid);
printf("Time Elapsed : %.6f sec\n", elapsed);
if (WIFEXITED(status)) {
printf("Exit Code : %d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("Terminated by Signal : %d\n", WTERMSIG(status));
}
printf("------------------------------\n");
}
return 0;
}
+15
View File
@@ -0,0 +1,15 @@
TARGET = echo
SRCS = echo.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)
+25
View File
@@ -0,0 +1,25 @@
#include <stdio.h>
#include <string.h>
int main(int argc, 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");
}
return 0;
}
+17
View File
@@ -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)
+172
View File
@@ -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++;
}
}
+23
View File
@@ -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
+244
View File
@@ -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;
}
+7
View File
@@ -0,0 +1,7 @@
#ifndef PARA_H
#define PARA_H
#define MAX_CMD_LEN 1024
#define MAX_ARGS 64
#endif // PARA_H
+15
View File
@@ -0,0 +1,15 @@
TARGET = grep
SRCS = grep.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)
+53
View File
@@ -0,0 +1,53 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE 1024
// 사용법:
// 1. 파일 읽기: grep <pattern> <filename>
// 2. 파이프(Stdin): cat file | grep <pattern>
int main(int argc, char *argv[]) {
// 최소한 패턴은 있어야 함
if (argc < 2) {
printf("Usage: grep <pattern> [filename]\n");
return 1;
}
char *pattern = argv[1];
FILE *fp;
// 인자가 2개면 (grep pattern) -> 표준 입력(stdin) 사용
if (argc == 2) {
fp = stdin;
}
// 인자가 3개 이상이면 (grep pattern file) -> 파일 열기
else {
fp = fopen(argv[2], "r");
if (!fp) {
perror("grep");
return 1;
}
}
char line[MAX_LINE];
// fp가 파일이든 stdin이든 똑같이 읽음
while (fgets(line, sizeof(line), fp)) {
// strstr: 부분 문자열 찾기
if (strstr(line, pattern) != NULL) {
printf("%s", line);
// 입력에 개행이 없는 경우(드물지만)를 대비해 안전장치
// (보통 fgets가 개행까지 읽어오므로 중복 개행 방지 로직 필요시 추가)
// 여기서는 단순하게 그대로 출력
}
}
// 파일일 때만 닫아줌 (stdin은 닫으면 안 됨)
if (argc > 2) {
fclose(fp);
}
return 0;
}
+15
View File
@@ -0,0 +1,15 @@
TARGET = hello
SRCS = hello.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)
+5
View File
@@ -0,0 +1,5 @@
#include <stdio.h>
int main() {
printf("Hello! I am a completely separate program.\n");
return 0;
}
+15
View File
@@ -0,0 +1,15 @@
TARGET = ifconfig
SRCS = ifconfig.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)
+73
View File
@@ -0,0 +1,73 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h> // ifreq
#include <arpa/inet.h> // inet_pton, sockaddr_in
#include <errno.h>
// 사용법: ifconfig eth0 10.0.2.15
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("Usage: ifconfig <interface> <ip_address>\n");
return 1;
}
char *ifname = argv[1];
char *ip_str = argv[2];
// 1. 커널과 대화하기 위한 소켓 생성 (DGRAM: UDP)
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
perror("socket");
return 1;
}
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
// 인터페이스 이름 설정 (예: eth0)
strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);
// 2. IP 주소 설정 (SIOCSIFADDR)
struct sockaddr_in *addr = (struct sockaddr_in *)&ifr.ifr_addr;
addr->sin_family = AF_INET;
// 문자열 IP -> 바이너리 변환
if (inet_pton(AF_INET, ip_str, &addr->sin_addr) != 1) {
fprintf(stderr, "Invalid IP format\n");
close(fd);
return 1;
}
if (ioctl(fd, SIOCSIFADDR, &ifr) < 0) {
perror("ioctl(SIOCSIFADDR) - Failed to set IP");
close(fd);
return 1;
}
printf("IP %s assigned to %s\n", ip_str, ifname);
// 3. 인터페이스 활성화 (UP & RUNNING) (SIOCGIFFLAGS -> SIOCSIFFLAGS)
// 현재 플래그 가져오기
if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
perror("ioctl(SIOCGIFFLAGS)");
close(fd);
return 1;
}
// UP 플래그와 RUNNING 플래그 추가
ifr.ifr_flags |= (IFF_UP | IFF_RUNNING);
// 플래그 다시 설정
if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
perror("ioctl(SIOCSIFFLAGS) - Failed to set UP");
close(fd);
return 1;
}
printf("Interface %s is now UP\n", ifname);
close(fd);
return 0;
}
+15
View File
@@ -0,0 +1,15 @@
TARGET = medit
SRCS = medit.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)
+130
View File
@@ -0,0 +1,130 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#define MAX_LINES 1000
#define MAX_LEN 128
char buffer[MAX_LINES][MAX_LEN];
int line_count = 0;
char filename[64];
// 화면 지우기 (ANSI Code)
void clear_screen() {
printf("\033[2J\033[H");
}
// 현재 버퍼 내용 출력
void print_buffer() {
clear_screen();
printf("\033[1;33m=== %s ===\033[0m\n", filename);
for (int i = 0; i < line_count; i++) {
printf("\033[1;34m%3d |\033[0m %s\n", i + 1, buffer[i]);
}
printf("---------------------------------------------------\n");
printf("[Type text to append] [Cmds: :w (save), :q (quit), :d <num> (del)]\n");
}
// 파일 불러오기
void load_file() {
int fd = open(filename, O_RDONLY);
if (fd < 0) return; // 파일 없으면 새로 생성
char ch;
int buf_idx = 0;
while (read(fd, &ch, 1) > 0) {
if (ch == '\n') {
buffer[line_count][buf_idx] = '\0';
line_count++;
buf_idx = 0;
if (line_count >= MAX_LINES) break;
} else {
if (buf_idx < MAX_LEN - 1) {
buffer[line_count][buf_idx++] = ch;
}
}
}
close(fd);
}
// 파일 저장하기
void save_file() {
int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd < 0) {
perror("save failed");
return;
}
for (int i = 0; i < line_count; i++) {
write(fd, buffer[i], strlen(buffer[i]));
write(fd, "\n", 1);
}
close(fd);
printf("Saved to %s\n", filename);
sleep(1); // 저장 메시지 확인용
}
// 라인 삭제
void delete_line(int line_num) {
if (line_num < 1 || line_num > line_count) {
printf("Invalid line number\n");
sleep(1);
return;
}
// 뒤의 라인들을 앞으로 당김
for (int i = line_num - 1; i < line_count - 1; i++) {
strcpy(buffer[i], buffer[i+1]);
}
line_count--;
}
int main(int argc, char *argv[]) {
if (argc < 2) {
printf("Usage: medit <filename>\n");
return 1;
}
strncpy(filename, argv[1], 63);
load_file();
char input[MAX_LEN + 10]; // 명령어 포함 여유분
while (1) {
print_buffer();
printf("> ");
if (fgets(input, sizeof(input), stdin) == NULL) break;
input[strcspn(input, "\n")] = 0; // 개행 제거
// 명령어 처리 (:)
if (input[0] == ':') {
if (strcmp(input, ":q") == 0) {
break;
} else if (strcmp(input, ":w") == 0) {
save_file();
} else if (strncmp(input, ":d", 2) == 0) {
int ln = atoi(input + 3);
delete_line(ln);
} else {
printf("Unknown command. :w, :q, :d <num>\n");
sleep(1);
}
}
// 일반 텍스트 입력 (추가)
else {
if (line_count < MAX_LINES) {
strncpy(buffer[line_count], input, MAX_LEN - 1);
buffer[line_count][MAX_LEN - 1] = '\0';
line_count++;
} else {
printf("Buffer full!\n");
sleep(1);
}
}
}
return 0;
}
+15
View File
@@ -0,0 +1,15 @@
TARGET = mkdir
SRCS = mkdir.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)
+18
View File
@@ -0,0 +1,18 @@
#include <stdio.h>
#include <sys/stat.h>
#include <errno.h>
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: mkdir <dirname>\n");
return 1;
}
// 0755: 권한 (rwxr-xr-x)
if (mkdir(argv[1], 0755) < 0) {
perror("mkdir");
return 1;
}
return 0;
}
+15
View File
@@ -0,0 +1,15 @@
TARGET = nc
SRCS = nc.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)
+132
View File
@@ -0,0 +1,132 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <errno.h>
#define BUF_SIZE 1024
// 에러 처리 헬퍼
void error_exit(char *msg) {
perror(msg);
exit(1);
}
void loop(int sockfd) {
fd_set read_fds;
char buf[BUF_SIZE];
int max_fd = sockfd > STDIN_FILENO ? sockfd : STDIN_FILENO;
int stdin_eof = 0; // [NEW] 입력 종료 여부 플래그
while (1) {
FD_ZERO(&read_fds);
// [NEW] 입력이 아직 안 끝났을 때만 STDIN 감시
if (!stdin_eof) {
FD_SET(STDIN_FILENO, &read_fds);
}
FD_SET(sockfd, &read_fds); // 소켓은 항상 감시
if (select(max_fd + 1, &read_fds, NULL, NULL, NULL) < 0) {
if (errno == EINTR) continue;
error_exit("select");
}
// 1. 키보드/파일 입력 -> 소켓 전송
if (!stdin_eof && FD_ISSET(STDIN_FILENO, &read_fds)) {
int n = read(STDIN_FILENO, buf, BUF_SIZE);
if (n < 0) error_exit("read stdin");
if (n == 0) {
// [NEW] EOF(파일 끝) 도달 시:
// 즉시 종료하지 않고, "나는 보낼 거 다 보냈다"고 표시만 함
stdin_eof = 1;
// (선택사항) TCP Half-Close: 서버에게 "보낼 거 끝났다"고 알림
shutdown(sockfd, SHUT_WR);
} else {
if (write(sockfd, buf, n) < 0) error_exit("write to socket");
}
}
// 2. 소켓 수신 -> 화면 출력
if (FD_ISSET(sockfd, &read_fds)) {
int n = read(sockfd, buf, BUF_SIZE);
if (n < 0) error_exit("read socket");
if (n == 0) {
// [NEW] 서버가 연결을 끊었을 때 비로소 루프 종료!
break;
}
if (write(STDOUT_FILENO, buf, n) < 0) error_exit("write to stdout");
}
}
}
int main(int argc, char *argv[]) {
if (argc < 3) {
printf("Usage:\n");
printf(" Connect: nc <IP> <PORT>\n");
printf(" Listen : nc -l <PORT>\n");
return 1;
}
int sockfd;
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
// --- Server Mode (-l) ---
if (strcmp(argv[1], "-l") == 0) {
int port = atoi(argv[2]);
int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd < 0) error_exit("socket");
// 주소 재사용 허용 (Time-wait 방지)
int opt = 1;
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(port);
if (bind(listen_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) error_exit("bind");
if (listen(listen_fd, 1) < 0) error_exit("listen");
printf("Listening on port %d...\n", port);
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
sockfd = accept(listen_fd, (struct sockaddr*)&client_addr, &client_len);
if (sockfd < 0) error_exit("accept");
printf("Connection from %s\n", inet_ntoa(client_addr.sin_addr));
close(listen_fd); // 더 이상 리스닝 안 함 (1:1 채팅)
}
// --- Client Mode ---
else {
char *ip = argv[1];
int port = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) error_exit("socket");
addr.sin_port = htons(port);
if (inet_pton(AF_INET, ip, &addr.sin_addr) <= 0) error_exit("invalid address");
printf("Connecting to %s:%d...\n", ip, port);
if (connect(sockfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) error_exit("connect");
printf("Connected!\n");
}
// 데이터 교환 루프 진입
loop(sockfd);
close(sockfd);
return 0;
}
+15
View File
@@ -0,0 +1,15 @@
TARGET = rm
SRCS = rm.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)
+17
View File
@@ -0,0 +1,17 @@
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: rm <filename>\n");
return 1;
}
if (unlink(argv[1]) < 0) {
perror("rm");
return 1;
}
return 0;
}
+15
View File
@@ -0,0 +1,15 @@
TARGET = route
SRCS = route.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)
+62
View File
@@ -0,0 +1,62 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/route.h> // struct rtentry
#include <arpa/inet.h>
// 사용법: route add default gw <GATEWAY_IP>
int main(int argc, char *argv[]) {
// 파싱을 간단하게 하기 위해 고정된 포맷만 지원
if (argc != 5 || strcmp(argv[1], "add") != 0 ||
strcmp(argv[2], "default") != 0 || strcmp(argv[3], "gw") != 0) {
printf("Usage: route add default gw <GATEWAY_IP>\n");
return 1;
}
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("socket");
return 1;
}
struct rtentry rt;
memset(&rt, 0, sizeof(rt));
// 1. 목적지 (Destination): 0.0.0.0 (모든 주소)
struct sockaddr_in *dst = (struct sockaddr_in *)&rt.rt_dst;
dst->sin_family = AF_INET;
dst->sin_addr.s_addr = INADDR_ANY;
// 2. 마스크 (Genmask): 0.0.0.0 (모든 비트 허용)
struct sockaddr_in *mask = (struct sockaddr_in *)&rt.rt_genmask;
mask->sin_family = AF_INET;
mask->sin_addr.s_addr = INADDR_ANY;
// 3. 게이트웨이 (Gateway): 입력받은 IP (예: 10.0.2.2)
struct sockaddr_in *gw = (struct sockaddr_in *)&rt.rt_gateway;
gw->sin_family = AF_INET;
if (inet_pton(AF_INET, argv[4], &gw->sin_addr) <= 0) {
printf("Invalid Gateway IP\n");
close(sockfd);
return 1;
}
// 4. 플래그 설정
// RTF_UP: 경로 활성화
// RTF_GATEWAY: 목적지가 게이트웨이임
rt.rt_flags = RTF_UP | RTF_GATEWAY;
// 5. 커널에 라우팅 테이블 추가 요청 (SIOCADDRT)
if (ioctl(sockfd, SIOCADDRT, &rt) < 0) {
perror("route add");
close(sockfd);
return 1;
}
printf("Default gateway set to %s\n", argv[4]);
close(sockfd);
return 0;
}
+15
View File
@@ -0,0 +1,15 @@
TARGET = sui
SRCS = sui.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)
+11
View File
@@ -0,0 +1,11 @@
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
if(argc <= 1) return 0;
for(int i=0;i<argc;i++)
{
printf("[%s]%c", argv[i], (i==argc-1?'\n':' '));
}
return atoi(argv[1]);
}
+15
View File
@@ -0,0 +1,15 @@
TARGET = touch
SRCS = touch.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)
+24
View File
@@ -0,0 +1,24 @@
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: touch <filename>\n");
return 1;
}
// O_CREAT: 없으면 생성
// O_TRUNC: 있으면 내용을 비움 (0바이트로 만듦)
// 0644: 파일 권한 (rw-r--r--)
int fd = open(argv[1], O_CREAT | O_TRUNC | O_WRONLY, 0644);
if (fd < 0) {
perror("touch");
return 1;
}
close(fd);
return 0;
}
+15
View File
@@ -0,0 +1,15 @@
TARGET = wg
SRCS = wg.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)
+125
View File
@@ -0,0 +1,125 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <errno.h>
#define BUF_SIZE 4096
// 요청 메시지 구조체 (패딩 문제 방지를 위해 바이트 배열로 관리)
struct req_t {
struct nlmsghdr n;
char buf[BUF_SIZE];
};
// 속성 추가 (RTA_APPEND)
// 커널의 표준 방식대로 테일 포인터를 이동시키며 추가
int addattr_l(struct req_t *req, int type, const void *data, int alen) {
int len = RTA_LENGTH(alen);
struct rtattr *rta;
// 현재 메시지 길이 (헤더 포함)
int msg_len = req->n.nlmsg_len;
if (NLMSG_ALIGN(msg_len) + RTA_ALIGN(len) > sizeof(struct req_t)) {
fprintf(stderr, "addattr_l: Message too long\n");
return -1;
}
// 데이터가 들어갈 위치 계산
rta = (struct rtattr *)(((char *)&req->n) + NLMSG_ALIGN(msg_len));
rta->rta_type = type;
rta->rta_len = len;
if (alen) {
memcpy(RTA_DATA(rta), data, alen);
}
// 메시지 전체 길이 업데이트
req->n.nlmsg_len = NLMSG_ALIGN(msg_len) + RTA_ALIGN(len);
return 0;
}
// 중첩 속성 시작 (Nested Start)
struct rtattr *addattr_nest(struct req_t *req, int type) {
struct rtattr *nest = (struct rtattr *)(((char *)&req->n) + NLMSG_ALIGN(req->n.nlmsg_len));
// 빈 속성 추가 (일단 데이터 없이)
if (addattr_l(req, type, NULL, 0) < 0) return NULL;
return nest;
}
// 중첩 속성 끝 (Nested End)
void addattr_nest_end(struct req_t *req, struct rtattr *nest) {
// 중첩 속성의 길이는 (현재 전체 길이) - (중첩 속성 시작 위치)
nest->rta_len = (char *)&req->n + req->n.nlmsg_len - (char *)nest;
}
int main(int argc, char *argv[]) {
if (argc != 3 || strcmp(argv[1], "create") != 0) {
printf("Usage: wg create <interface_name>\n");
return 1;
}
char *ifname = argv[2];
int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (fd < 0) { perror("socket"); return 1; }
struct req_t req;
memset(&req, 0, sizeof(req));
// 1. 헤더 설정
// 초기 길이는 헤더 + ifinfomsg 구조체 크기
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
req.n.nlmsg_type = RTM_NEWLINK;
req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK;
struct ifinfomsg *ifi = (struct ifinfomsg *)NLMSG_DATA(&req.n);
ifi->ifi_family = AF_UNSPEC;
// 2. IFLA_IFNAME: 인터페이스 이름 ("wg0")
// 문자열은 반드시 NULL 문자 포함 길이 (+1)
addattr_l(&req, IFLA_IFNAME, ifname, strlen(ifname) + 1);
// 3. IFLA_LINKINFO: 링크 정보 시작
struct rtattr *linkinfo = addattr_nest(&req, IFLA_LINKINFO);
// 4. IFLA_INFO_KIND: 타입 ("wireguard")
addattr_l(&req, IFLA_INFO_KIND, "wireguard", strlen("wireguard") + 1);
// 링크 정보 종료
addattr_nest_end(&req, linkinfo);
// 디버깅: 전송할 패킷 크기 출력
// printf("Sending Netlink Msg: %d bytes\n", req.n.nlmsg_len);
// 5. 전송
if (send(fd, &req.n, req.n.nlmsg_len, 0) < 0) {
perror("send");
close(fd);
return 1;
}
// 6. 응답 수신
char buf[BUF_SIZE];
int len = recv(fd, buf, sizeof(buf), 0);
if (len < 0) { perror("recv"); return 1; }
struct nlmsghdr *nh = (struct nlmsghdr *)buf;
if (nh->nlmsg_type == NLMSG_ERROR) {
struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(nh);
if (err->error == 0) {
printf("WireGuard interface '%s' created successfully!\n", ifname);
} else {
fprintf(stderr, "RTNETLINK error: %s (%d)\n", strerror(-err->error), -err->error);
return 1;
}
}
close(fd);
return 0;
}
+14
View File
@@ -0,0 +1,14 @@
TARGET = xxd
SRCS = xxd.c
CC = gcc
CFLAGS = -static -Wall
OUT_BIN ?= $(TARGET)
all: $(OUT_BIN)
$(OUT_BIN): $(SRCS)
$(CC) $(CFLAGS) -o $@ $^
clean:
rm -f $(TARGET) *.o
+84
View File
@@ -0,0 +1,84 @@
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#define MAX_COLS 256
int main(int argc, char *argv[]) {
int fd = 0;
unsigned char buf[MAX_COLS];
int n;
unsigned int offset = 0;
int cols = 16;
char *filename = NULL;
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "-l") == 0) {
if (i + 1 < argc) {
cols = atoi(argv[++i]);
if (cols <= 0 || cols > MAX_COLS) {
printf("xxd: invalid column length (1-%d)\n", MAX_COLS);
return 1;
}
} else {
printf("xxd: option -l requires an argument\n");
return 1;
}
} else {
filename = argv[i];
}
}
// 2. 파일 열기
if (filename != NULL) {
fd = open(filename, O_RDONLY);
if (fd < 0) {
perror("xxd");
return 1;
}
}
// 3. 읽기 및 출력 루프
// sizeof(buf)가 아니라 설정된 cols 만큼 읽어야 함
while ((n = read(fd, buf, cols)) > 0) {
// (1) 오프셋 출력
printf("%08x: ", offset);
// (2) Hex 데이터 출력
for (int i = 0; i < cols; i++) {
// 2바이트마다 그룹핑 (가독성)
if (i % 2 == 0) printf(" ");
if (i < n) {
// 데이터가 있으면 출력
printf("%02x", buf[i]);
} else {
// 데이터가 없으면 공백 채움 (Padding)
printf(" ");
}
}
printf(" ");
// (3) ASCII 문자 출력
for (int i = 0; i < n; i++) {
if (isprint(buf[i])) {
printf("%c", buf[i]);
} else {
printf(".");
}
}
printf("\n");
offset += n;
}
if (filename != NULL) close(fd);
return 0;
}