This commit is contained in:
pathetic 2025-05-13 14:20:43 +01:00
parent 31d1a64bba
commit 9d759fcee7
3 changed files with 281 additions and 137 deletions

View file

@ -1,45 +1,65 @@
global _start
global sys_read
global sys_write
global sys_fork
global sys_execve
global sys_wait4
global sys_exit
extern main
global _start
global sys_open
global sys_close
global sys_getdents64
global sys_stat
global sys_write
global sys_read
global sys_wait4
global sys_exit
global environ
section .text
extern main
section .data
environ: dq 0
section .text
sys_open:
mov rax, 2 ; __NR_open
syscall
ret
sys_close:
mov rax, 3 ; __NR_close
syscall
ret
sys_getdents64:
mov rax, 217 ; __NR_getdents64
syscall
ret
sys_stat:
mov rax, 4 ; __NR_stat (legacy)
syscall
ret
sys_read:
mov rax, 0
mov rax, 0 ; __NR_read
syscall
ret
sys_write:
mov rax, 1
syscall
ret
sys_fork:
mov rax, 57
syscall
ret
sys_execve:
mov rax, 59
mov rax, 1 ; __NR_write
syscall
ret
sys_wait4:
mov rax, 61
mov rax, 61 ; __NR_wait4
syscall
ret
sys_exit:
mov rax, 60
mov rax, 60 ; __NR_exit
syscall
ret
_start:
call main
mov rdi, rax
mov rax, 60
; SysV ABI: rdi=argc, rsi=argv, rdx=envp
mov [rel environ], rdx
call main
mov rdi, rax ; exit code = return value of main
mov rax, 60 ; __NR_exit
syscall

View file

@ -6,48 +6,97 @@ extern "C" {
#endif
typedef unsigned long size_t;
typedef long off_t;
typedef long off_t;
#define NULL ((void*)0)
#define O_RDONLY 0
#define O_WRONLY 1
#define O_RDWR 2
#define O_CREAT 64
#define O_TRUNC 512
#define O_APPEND 1024
#define O_CLOEXEC 02000000
extern char **environ;
char *getenv(const char *name);
/* minimal open flags */
#define O_RDONLY 0
#define O_WRONLY 1
#define O_RDWR 2
#define O_CREAT 64
#define O_TRUNC 512
#define O_APPEND 1024
#define O_CLOEXEC 02000000
/* minimal stdarg */
typedef __builtin_va_list va_list;
#define va_start(ap,last) __builtin_va_start(ap,last)
#define va_arg(ap,type) __builtin_va_arg(ap,type)
#define va_end(ap) __builtin_va_end(ap)
#define va_arg(ap,type) __builtin_va_arg(ap,type)
#define va_end(ap) __builtin_va_end(ap)
#define SYS_READ 0
#define SYS_WRITE 1
#define SYS_OPEN 2
#define SYS_CLOSE 3
#define SYS_LSEEK 8
/* syscall numbers */
#define SYS_READ 0
#define SYS_WRITE 1
#define SYS_OPEN 2
#define SYS_CLOSE 3
#define SYS_LSEEK 8
static inline long _syscall3(long nr,long a1,long a2,long a3){long ret;asm volatile("syscall":"=a"(ret):"a"(nr),"D"(a1),"S"(a2),"d"(a3):"rcx","r11","memory");return ret;}
/* raw syscall wrapper */
static inline long _syscall3(long nr, long a1, long a2, long a3) {
long ret;
asm volatile(
"syscall"
: "=a"(ret)
: "a"(nr), "D"(a1), "S"(a2), "d"(a3)
: "rcx","r11","memory"
);
return ret;
}
#ifndef MY_BUFSIZ
#define MY_BUFSIZ 4096
#endif
typedef struct{int fd;char buf[MY_BUFSIZ];size_t pos;size_t len;int mode;}MY_FILE;
typedef struct {
int fd;
char buf[MY_BUFSIZ];
size_t pos;
size_t len;
int mode;
} MY_FILE;
MY_FILE* my_fopen(const char* path,int flags,int mode);
int my_fclose(MY_FILE* f);
size_t my_fread(void* ptr,size_t size,size_t nmemb,MY_FILE* f);
size_t my_fwrite(const void* ptr,size_t size,size_t nmemb,MY_FILE* f);
int my_putc(int c,MY_FILE* f);
int my_puts(const char* s,MY_FILE* f);
off_t my_seek(MY_FILE* f,off_t offset,int whence);
int my_printf(MY_FILE* f,const char* fmt,...);
int my_vprintf(MY_FILE* f,const char* fmt,va_list ap);
MY_FILE *my_fopen(const char *path, int flags, int mode);
int my_fclose(MY_FILE *f);
size_t my_fread(void *ptr, size_t size, size_t nmemb, MY_FILE *f);
size_t my_fwrite(const void *ptr, size_t size, size_t nmemb, MY_FILE *f);
int my_putc(int c, MY_FILE *f);
int my_puts(const char *s, MY_FILE *f);
off_t my_seek(MY_FILE *f, off_t offset, int whence);
int my_printf(MY_FILE *f, const char *fmt, ...);
int my_vprintf(MY_FILE *f, const char *fmt, va_list ap);
struct linux_dirent64 {
unsigned long d_ino;
off_t d_off;
unsigned short d_reclen;
unsigned char d_type;
char d_name[];
};
struct stat_t {
unsigned long st_dev;
unsigned long st_ino;
unsigned long st_nlink;
unsigned int st_mode;
unsigned int st_uid;
unsigned int st_gid;
unsigned long st_rdev;
unsigned long st_size;
unsigned long st_blksize;
unsigned long st_blocks;
unsigned long st_atime;
unsigned long st_atime_nsec;
unsigned long st_mtime;
unsigned long st_mtime_nsec;
unsigned long st_ctime;
unsigned long st_ctime_nsec;
};
#ifdef __cplusplus
}
#endif
#endif
#endif /* MINI_STDIO_H */

View file

@ -1,114 +1,189 @@
#include "headers/nstdo.h"
extern long sys_read(int fd, void *buf, size_t cnt);
extern long sys_write(int fd, const void *buf, size_t cnt);
extern long sys_fork(void);
extern long sys_execve(const char *filename, char *const argv[], char *const envp[]);
extern long sys_wait4(int pid, int *wstatus, int options, void *rusage);
extern long sys_open(const char *pathname, int flags, int mode);
extern long sys_close(int fd);
extern long sys_getdents64(int fd, void *dirp, size_t count);
extern long sys_stat(const char *pathname, struct stat_t *statbuf);
extern long sys_write(int fd, const void *buf, size_t count);
extern long sys_read(int fd, void *buf, size_t count);
extern void sys_exit(int status);
static int streq(const char *a, const char *b) {
while (*a && *b) {
if (*a != *b) return 0;
a++;
b++;
if (*a++ != *b++) return 0;
}
return *a == *b;
}
static long str_len(const char *s) {
long len = 0;
while (s[len]) len++;
return len + 1; // Include the null terminator in the length
long l = 0;
while (s[l]) l++;
return l;
}
static void fancyMessage(void) {
const char *fM1 = "+-------------------------------------------------+\n";
const char *fM2 = "| |\n";
const char *fM3 = "| Welcome to the Mini Shell! |\n";
const char *fM4 = "| |\n";
const char *fM5 = "| Type 'help' to view all 16 commands. |\n";
const char *fM6 = "| Type 'exit' to leave the shell. |\n";
const char *fM7 = "| |\n";
const char *fM8 = "| Have a productive coding session! |\n";
const char *fM9 = "| |\n";
const char *fM0 = "+-------------------------------------------------+\n";
sys_write(1, fM1, str_len(fM1));
sys_write(1, fM2, str_len(fM2));
sys_write(1, fM3, str_len(fM3));
sys_write(1, fM4, str_len(fM4));
sys_write(1, fM5, str_len(fM5));
sys_write(1, fM6, str_len(fM6));
sys_write(1, fM7, str_len(fM7));
sys_write(1, fM8, str_len(fM8));
sys_write(1, fM9, str_len(fM9));
sys_write(1, fM0, str_len(fM0));
sys_write(1, "\n", 1);
sys_write(1, "\n", 1);
}
static void helpCommand(void) {
const char *helpText[] = {
"Available commands:\n\n",
"\tcd <path>\t\tChange the current directory to <path>\n",
"\tls [-l] [dir]\t\tList the contents of the directory [dir] (default: current directory), with an optional long format (-l)\n",
"\thistory\t\t\tDisplay the command history\n",
"\thelp\t\t\tShow this help message\n",
"\tpwd\t\t\tPrint the current working directory\n",
"\tclear\t\t\tClear the terminal screen\n",
"\ttouch <filename>\tCreate an empty file named <filename>\n",
"\tcat <filename>\t\tDisplay the contents of <filename>\n",
"\trm <filename>\t\tRemove the specified file\n",
"\tmkdir <dir>\t\tCreate a directory named <dir>\n",
"\trmdir <dir>\t\tRemove a directory named <dir>\n",
"\techo <text>\t\tDisplay the text <text>\n",
"\tman <command>\t\tDisplay help for the specified command (e.g., 'man ls')\n",
"\tcp <source> <dest>\tCopy a file from <source> to <dest>\n",
"\tmv <source> <dest>\tMove or rename a file from <source> to <dest>\n",
"\thead <filename>\t\tDisplay the first 10 lines of <filename>\n",
"\tnano <filename>\t\tEdit <filename> in a simple text editor\n",
"\nFor more detailed information on a specific command, use 'man <command>'.\n"
};
for (size_t i = 0; i < sizeof(helpText) / sizeof(helpText[0]); i++) {
sys_write(1, helpText[i], str_len(helpText[i]));
static int utoa(unsigned long v, char *buf) {
char tmp[32];
int i = 0;
if (v == 0) {
buf[0] = '0';
return 1;
}
while (v) {
tmp[i++] = '0' + (v % 10);
v /= 10;
}
for (int j = 0; j < i; j++) {
buf[j] = tmp[i - 1 - j];
}
return i;
}
static int prefix_eq(const char *s, const char *t, long n) {
for (long i = 0; i < n; i++) {
if (s[i] != t[i]) return 0;
}
return 1;
}
char *getenv(const char *name) {
if (!environ || !name) return NULL;
long keylen = 0;
while (name[keylen]) keylen++;
for (char **ep = environ; *ep; ep++) {
if (prefix_eq(*ep, name, keylen) && (*ep)[keylen] == '=') {
return &(*ep)[keylen + 1];
}
}
return NULL;
}
static void lsCommand(const char *path, int longFlag) {
if (!path || !*path) path = ".";
long fd = sys_open(path, 0, 0);
if (fd < 0) {
const char *err = "Error: cannot open directory\n";
sys_write(1, err, str_len(err));
return;
}
char dentbuf[8192];
while (1) {
long nread = sys_getdents64(fd, dentbuf, sizeof(dentbuf));
if (nread <= 0) break;
long bpos = 0;
while (bpos < nread) {
struct linux_dirent64 *d =
(struct linux_dirent64 *)(dentbuf + bpos);
char *name = d->d_name;
if (d->d_ino) {
char full[1024];
int off = 0;
long plen = str_len(path);
for (long i = 0; i < plen; i++) full[off++] = path[i];
if (plen && path[plen - 1] != '/') full[off++] = '/';
for (int i = 0; name[i]; i++) full[off++] = name[i];
full[off] = '\0';
struct stat_t st;
sys_stat(full, &st);
char out[2048];
int o = 0;
char numbuf[32];
if (longFlag) {
unsigned int m = st.st_mode;
out[o++] = (m & 0040000) ? 'd' : '-';
out[o++] = (m & 0000400) ? 'r' : '-';
out[o++] = (m & 0000200) ? 'w' : '-';
out[o++] = (m & 0000100) ? 'x' : '-';
out[o++] = (m & 0000040) ? 'r' : '-';
out[o++] = (m & 0000020) ? 'w' : '-';
out[o++] = (m & 0000010) ? 'x' : '-';
out[o++] = (m & 0000004) ? 'r' : '-';
out[o++] = (m & 0000002) ? 'w' : '-';
out[o++] = (m & 0000001) ? 'x' : '-';
out[o++] = ' ';
o += utoa(st.st_nlink, numbuf);
for (int i = 0; i < utoa(st.st_nlink, numbuf); i++)
out[o - utoa(st.st_nlink, numbuf) + i] = numbuf[i];
out[o++] = ' ';
o += utoa(st.st_uid, numbuf);
for (int i = 0; i < utoa(st.st_uid, numbuf); i++)
out[o - utoa(st.st_uid, numbuf) + i] = numbuf[i];
out[o++] = ' ';
o += utoa(st.st_gid, numbuf);
for (int i = 0; i < utoa(st.st_gid, numbuf); i++)
out[o - utoa(st.st_gid, numbuf) + i] = numbuf[i];
out[o++] = ' ';
}
o += utoa(st.st_size, numbuf);
for (int i = 0; i < utoa(st.st_size, numbuf); i++)
out[o - utoa(st.st_size, numbuf) + i] = numbuf[i];
out[o++] = '\t';
for (int i = 0; name[i]; i++) out[o++] = name[i];
out[o++] = '\n';
sys_write(1, out, o);
}
bpos += d->d_reclen;
}
}
sys_close(fd);
}
int main(int argc, char *argv[], char *envp[]) {
(void)argc;
(void)argv;
const char prompt[] = "lala@mini-shell> ";
(void)argc; (void)argv; (void)envp;
char buf[512];
fancyMessage();
const char *user = getenv("USER");
if (!user) user = getenv("LOGNAME");
if (!user) user = getenv("USERNAME");
if (!user) user = "user";
const char *host = "mini-shell";
char prompt[64];
int prompt_len = 0;
for (const char *p = user; *p; p++) prompt[prompt_len++] = *p;
prompt[prompt_len++] = '@';
for (const char *p = host; *p; p++) prompt[prompt_len++] = *p;
prompt[prompt_len++] = '>';
prompt[prompt_len++] = ' ';
while (1) {
sys_write(1, prompt, sizeof(prompt) - 1);
sys_write(1, prompt, prompt_len);
long n = sys_read(0, buf, sizeof(buf) - 1);
if (n <= 0) break;
buf[n - 1] = '\0';
if (streq(buf, "help")) {
helpCommand();
continue;
char *p = buf;
while (*p == ' ') p++;
char *cmd = p;
while (*p && *p != ' ') p++;
if (*p) *p++ = '\0';
char *opt = NULL;
char *arg = NULL;
while (*p == ' ') p++;
if (*p) {
opt = p;
while (*p && *p != ' ') p++;
if (*p) *p++ = '\0';
}
while (*p == ' ') p++;
if (*p) {
arg = p;
}
if (streq(buf, "exit")) {
if (streq(cmd, "exit")) {
break;
}
char *args[] = { buf, NULL };
long pid = sys_fork();
if (pid == 0) {
sys_execve(buf, args, envp);
sys_exit(1);
} else {
sys_wait4(pid, 0, 0, 0);
} else if (streq(cmd, "help")) {
const char *h = "Usage:\n ls [-l] [directory]\n exit\n";
sys_write(1, h, str_len(h));
} else if (streq(cmd, "ls")) {
int longFlag = (opt && streq(opt, "-l")) ? 1 : 0;
const char *path = arg ? arg : ".";
lsCommand(path, longFlag);
}
}