Added ls
This commit is contained in:
parent
31d1a64bba
commit
9d759fcee7
3 changed files with 281 additions and 137 deletions
|
|
@ -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
|
||||
syscall
|
||||
; 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
|
||||
|
|
@ -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 */
|
||||
241
src/main.c
241
src/main.c
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue