GMS Linux: start?
This commit is contained in:
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
@@ -0,0 +1,5 @@
|
||||
#include <stdio.h>
|
||||
int main() {
|
||||
printf("Hello! I am a completely separate program.\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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]);
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user