commit 9edcb271159648c4dc1ab9d9991a7a9cf0c59494
parent 801dbeeec59548cdb0c940cd91a43672846570a3
Author: evenfri <evenfri256@gmail.com>
Date: Mon, 5 Oct 2026 23:47:16 +0800
add l,fstat, fseek, update files
Diffstat:
31 files changed, 258 insertions(+), 93 deletions(-)
diff --git a/_exit.c b/_exit.c
@@ -6,7 +6,7 @@
#include "libc.h"
void _exit(int status) {
- syscall(SYS_exit, status);
+ syscall(SYS_exit, (long)status, 0, 0, 0, 0, 0);
for (;;) {}
}
diff --git a/calloc.c b/calloc.c
@@ -6,11 +6,12 @@
#include "libc.h"
void* calloc(size_t nmemb, size_t size) {
- size_t total = nmemb * size;
- if (nmemb != 0 && total / nmemb != size) {
+ if (nmemb != 0 && size > (size_t)-1 / nmemb) {
return NULL;
}
+ size_t total = nmemb * size;
+
void *ptr = malloc(total);
if (ptr != NULL) {
memset(ptr, 0, total);
diff --git a/chdir.c b/chdir.c
@@ -6,7 +6,7 @@
#include "libc.h"
int chdir(const char *path) {
- int ret = syscall(SYS_chdir, path);
+ int ret = syscall(SYS_chdir, (long)path, 0, 0, 0, 0, 0);
if (ret < 0) {
errno = -ret;
diff --git a/close.c b/close.c
@@ -6,7 +6,7 @@
#include "libc.h"
int close(int fd) {
- int ret = syscall(SYS_close, fd);
+ int ret = syscall(SYS_close, (long)fd, 0, 0, 0, 0, 0);
if (ret < 0) {
errno = -ret;
diff --git a/execve.c b/execve.c
@@ -6,7 +6,7 @@
#include "libc.h"
int execve(const char *path, char *const argv[], char *const envp[]) {
- int ret = syscall(SYS_execve, path, argv, envp);
+ int ret = syscall(SYS_execve, (long)path, (long)argv, (long)envp, 0, 0, 0);
if (ret < 0) {
errno = -ret;
diff --git a/execvp.c b/execvp.c
@@ -11,55 +11,78 @@ int execvp(const char *file, char *const argv[]) {
static char *empty_env[] = { NULL };
char **env = (environ != NULL) ? environ : empty_env;
- if (strchr(file, '/') != 0) {
+ if (file == NULL || *file == '\0') {
+ errno = ENOENT;
+ return -1;
+ }
+
+ if (strchr(file, '/') != NULL) {
return execve(file, argv, env);
}
const char *path_env = NULL;
- if (env != NULL) {
- for (char **ep = env; *ep != NULL; ++ep) {
- if (ep[0][0] == 'P' && ep[0][1] == 'A' &&
- ep[0][2] == 'T' && ep[0][3] == 'H' && ep[0][4] == '=') {
- path_env = *ep + 5;
- break;
- }
+ for (char **ep = env; *ep != NULL; ++ep) {
+ if (ep[0][0] == 'P' && ep[0][1] == 'A' &&
+ ep[0][2] == 'T' && ep[0][3] == 'H' && ep[0][4] == '=') {
+ path_env = *ep + 5;
+ break;
}
}
- if (path_env == NULL || *path_env == '\0') {
- path_env = "/bin";
+ if (path_env == NULL) {
+ path_env = "/bin:/usr/bin";
}
char path_buf[1024];
size_t file_len = strlen(file);
+ int saved_errno = ENOENT;
+
+ if (file_len >= sizeof(path_buf)) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
const char *p = path_env;
- while (*p != '\0') {
+ for (;;) {
const char *start = p;
while (*p != '\0' && *p != ':') {
p++;
}
- size_t dir_len = p - start;
+ size_t dir_len = (size_t)(p - start);
+ size_t needed = file_len + 1;
- if (dir_len == 0) {
- if (file_len + 1 < sizeof(path_buf)) {
- memcpy(path_buf, file, file_len + 1);
- execve(path_buf, argv, env);
+ if (dir_len != 0) {
+ if (dir_len > sizeof(path_buf) - needed - 1) {
+ saved_errno = ENAMETOOLONG;
+ goto next_path;
}
- } else {
- if (dir_len + 1 + file_len + 1 < sizeof(path_buf)) {
+ needed += dir_len + 1;
+ }
+
+ if (needed <= sizeof(path_buf)) {
+ if (dir_len == 0) {
+ memcpy(path_buf, file, file_len + 1);
+ } else {
memcpy(path_buf, start, dir_len);
path_buf[dir_len] = '/';
memcpy(path_buf + dir_len + 1, file, file_len + 1);
- execve(path_buf, argv, env);
}
+
+ if (execve(path_buf, argv, env) == -1) {
+ saved_errno = errno;
+ }
+ } else {
+ saved_errno = ENAMETOOLONG;
}
- if (*p == ':') {
- p++;
+next_path:
+ if (*p == '\0') {
+ break;
}
+ p++;
}
+ errno = saved_errno;
return -1;
}
diff --git a/fork.c b/fork.c
@@ -6,7 +6,7 @@
#include "libc.h"
int fork(void) {
- int ret = syscall(SYS_clone, (long)SIGCHLD, 0L, 0L, 0L, 0L);
+ int ret = syscall(SYS_clone, (long)SIGCHLD, 0, 0, 0, 0, 0);
if (ret < 0) {
errno = -ret;
diff --git a/fstat.c b/fstat.c
@@ -0,0 +1,17 @@
+/*
+ * fstat.c - fstat system call
+ * Copyright (C) 2026. All rights reserved.
+ */
+
+#include "libc.h"
+
+int fstat(int fd, struct stat *statbuf) {
+ int ret = syscall(SYS_fstat, (long)fd, (long)statbuf, 0, 0, 0, 0);
+
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+
+ return ret;
+}
diff --git a/getcwd.c b/getcwd.c
@@ -6,7 +6,7 @@
#include "libc.h"
char *getcwd(char *buf, size_t size) {
- int ret = syscall(SYS_getcwd, buf, size);
+ long ret = syscall(SYS_getcwd, (long)buf, (long)size, 0, 0, 0, 0);
if (ret < 0) {
errno = -ret;
diff --git a/getdents.c b/getdents.c
@@ -5,8 +5,8 @@
#include "libc.h"
-int getdents64(int fd, struct linux_dirent64 *dirp, unsigned int count) {
- int ret = syscall(SYS_getdents64, fd, (long)dirp, count);
+ssize_t getdents64(int fd, struct linux_dirent64 *dirp, size_t count) {
+ ssize_t ret = syscall(SYS_getdents64, (long)fd, (long)dirp, (long)count, 0, 0, 0);
if (ret < 0) {
errno = -ret;
return -1;
diff --git a/libc.h b/libc.h
@@ -9,7 +9,9 @@
/* base types */
typedef unsigned long size_t;
typedef unsigned long ulong_t;
+typedef unsigned long nfds_t;
typedef long ssize_t;
+typedef long off_t;
#ifndef NULL
#define NULL ((void*)0)
@@ -31,8 +33,57 @@ struct linux_dirent64 {
char d_name[];
};
+struct timespec {
+ long tv_sec;
+ long tv_nsec;
+};
+
+struct stat {
+ 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 int __pad0;
+ unsigned long st_rdev;
+ long st_size;
+ long st_blksize;
+ long st_blocks;
+ struct timespec st_atim;
+ struct timespec st_mtim;
+ struct timespec st_ctim;
+ long __reserved[3];
+};
+
+struct pollfd {
+ int fd;
+ short events;
+ short revents;
+};
+
+struct block_header {
+ size_t size;
+ size_t requested_size;
+ int is_free;
+ struct block_header *next;
+} __attribute__((aligned(16)));
+
+typedef struct block_header block_header_t;
+
+struct utimbuf {
+ long actime;
+ long modtime;
+};
+
+
#define SIGCHLD 17
+/* errno values used by the libc implementation */
+#define ENOENT 2
+#define EACCES 13
+#define ENAMETOOLONG 36
+
/* open flags */
#define O_RDONLY 00
#define O_WRONLY 01
@@ -46,6 +97,11 @@ struct linux_dirent64 {
#define SYS_write 1
#define SYS_open 2
#define SYS_close 3
+#define SYS_stat 4
+#define SYS_fstat 5
+#define SYS_lstat 6
+#define SYS_poll 7
+#define SYS_lseek 8
#define SYS_mmap 9
#define SYS_munmap 11
#define SYS_brk 12
@@ -73,7 +129,7 @@ struct linux_dirent64 {
extern char **environ;
/* syscall function */
-long syscall(long num, ...);
+long syscall(long num, long a1, long a2, long a3, long a4, long a5, long a6);
/* io */
ssize_t read(int fd, void *buf, size_t count);
@@ -97,7 +153,12 @@ int mkdir(const char *path, unsigned int mode);
int rmdir(const char *path);
int unlink(const char *path);
char *getcwd(char *buf, size_t size);
-int getdents64(int fd, struct linux_dirent64 *dirp, unsigned int count);
+ssize_t getdents64(int fd, struct linux_dirent64 *dirp, size_t count);
+int stat(const char *pathname, struct stat *statbuf);
+int fstat(int fd, struct stat *statbuf);
+int lstat(const char *pathname, struct stat *statbuf);
+int poll(struct pollfd *fds, nfds_t nfds, int timeout);
+off_t lseek(int fd, off_t offset, int whence);
/* memory */
void* mmap(void *addr, size_t length, int prot, int flags, int fd, long offset);
@@ -112,11 +173,6 @@ void* calloc(size_t nmemb, size_t size);
void* realloc(void *ptr, size_t size);
/* utime */
-struct utimbuf {
- long actime;
- long modtime;
-};
-
int utime(const char *path, const struct utimbuf *times);
/* string functions */
diff --git a/lseek.c b/lseek.c
@@ -0,0 +1,17 @@
+/*
+ * lseek.c - lseek system call
+ * Copyright (C) 2026. All rights reserved.
+ */
+
+#include "libc.h"
+
+off_t lseek(int fd, off_t offset, int whence) {
+ off_t ret = syscall(SYS_lseek, (long)fd, (long)offset, (long)whence, 0, 0, 0);
+
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+
+ return ret;
+}
diff --git a/lstat.c b/lstat.c
@@ -0,0 +1,17 @@
+/*
+ * lstat.c - lstat system call
+ * Copyright (C) 2026. All rights reserved.
+ */
+
+#include "libc.h"
+
+int lstat(const char *pathname, struct stat *statbuf) {
+ int ret = syscall(SYS_lstat, (long)pathname, (long)statbuf, 0, 0, 0, 0);
+
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+
+ return ret;
+}
diff --git a/malloc.c b/malloc.c
@@ -7,19 +7,17 @@
#define ALIGN_SIZE 16
#define ALIGN_MASK (ALIGN_SIZE - 1)
-
-struct block_header {
- size_t size;
- int is_free;
- struct block_header *next;
-} __attribute__((aligned(16)));
-
-typedef struct block_header block_header_t;
+#define MIN_ALLOC_SIZE 4096
static block_header_t *free_list = NULL;
-static size_t align(size_t n) {
- return (n + ALIGN_MASK) & ~ALIGN_MASK;
+static int align_size(size_t n, size_t *result) {
+ if (n > (size_t)-1 - ALIGN_MASK) {
+ return -1;
+ }
+
+ *result = (n + ALIGN_MASK) & ~ALIGN_MASK;
+ return 0;
}
void* malloc(size_t size) {
@@ -27,20 +25,29 @@ void* malloc(size_t size) {
return NULL;
}
- size_t total_size = align(size + sizeof(block_header_t));
- block_header_t *curr = free_list;
+ if (size > (size_t)-1 - sizeof(block_header_t)) {
+ return NULL;
+ }
+
+ size_t total_size;
+ if (align_size(size + sizeof(block_header_t), &total_size) < 0) {
+ return NULL;
+ }
+
+ block_header_t *curr = free_list;
block_header_t *prev = NULL;
while (curr != NULL) {
if (curr->is_free && curr->size >= total_size) {
curr->is_free = 0;
+ curr->requested_size = size;
return (void*)(curr + 1);
}
prev = curr;
curr = curr->next;
}
- size_t alloc_size = total_size < 4096 ? 4096 : total_size;
+ size_t alloc_size = total_size < MIN_ALLOC_SIZE ? MIN_ALLOC_SIZE : total_size;
block_header_t *block = mmap(NULL, alloc_size,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS,
@@ -51,6 +58,7 @@ void* malloc(size_t size) {
}
block->size = alloc_size;
+ block->requested_size = size;
block->is_free = 0;
block->next = NULL;
@@ -70,4 +78,5 @@ void free(void *ptr) {
block_header_t *header = (block_header_t*)ptr - 1;
header->is_free = 1;
+ header->requested_size = 0;
}
diff --git a/mkdir.c b/mkdir.c
@@ -6,7 +6,7 @@
#include "libc.h"
int mkdir(const char *path, unsigned int mode) {
- int ret = syscall(SYS_mkdir, path, mode);
+ int ret = syscall(SYS_mkdir, (long)path, (long)mode, 0, 0, 0, 0);
if (ret < 0) {
errno = -ret;
diff --git a/mkfile b/mkfile
@@ -31,6 +31,11 @@ ofiles = start.$o \
rmdir.$o \
unlink.$o \
getdents.$o \
+ stat.$o \
+ fstat.$o \
+ lstat.$o \
+ poll.$o \
+ lseek.$o \
utime.$o \
errno.$o \
strlen.$o \
diff --git a/mmap.c b/mmap.c
@@ -6,8 +6,8 @@
#include "libc.h"
void* mmap(void *addr, size_t length, int prot, int flags, int fd, long offset) {
- long ret = syscall(SYS_mmap, addr, length, prot, (long)flags, (long)fd,
- offset);
+ long ret = syscall(SYS_mmap, (long)addr, (long)length, (long)prot,
+ (long)flags, (long)fd, (long)offset);
if (ret < 0) {
errno = -ret;
diff --git a/mount.c b/mount.c
@@ -8,12 +8,13 @@
int mount(const char *src, const char *trg, const char *fstype, ulong_t flags,
const void *data) {
- int ret = syscall(SYS_mount,
- src,
- trg,
- fstype,
- flags,
- data);
+ int ret = syscall(SYS_mount,
+ (long)src,
+ (long)trg,
+ (long)fstype,
+ (long)flags,
+ (long)data,
+ 0);
if (ret < 0) {
errno = -ret;
diff --git a/munmap.c b/munmap.c
@@ -6,7 +6,7 @@
#include "libc.h"
int munmap(void *addr, size_t length) {
- long ret = syscall(SYS_munmap, addr, length);
+ long ret = syscall(SYS_munmap, (long)addr, (long)length, 0, 0, 0, 0);
if (ret < 0) {
errno = -ret;
diff --git a/open.c b/open.c
@@ -6,7 +6,7 @@
#include "libc.h"
int open(const char *filename, int flags, int mode) {
- int ret = syscall(SYS_open, filename, flags, mode);
+ int ret = syscall(SYS_open, (long)filename, (long)flags, (long)mode, 0, 0, 0);
if (ret < 0) {
errno = -ret;
diff --git a/poll.c b/poll.c
@@ -0,0 +1,17 @@
+/*
+ * poll.c - pollsystem call
+ * Copyright (C) 2026. All rights reserved.
+ */
+
+#include "libc.h"
+
+int poll(struct pollfd *fds, nfds_t nfds, int timeout) {
+ int ret = syscall(SYS_poll, (long)fds, (long)nfds, (long)timeout, 0, 0, 0);
+
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+
+ return ret;
+}
diff --git a/read.c b/read.c
@@ -6,7 +6,7 @@
#include "libc.h"
ssize_t read(int fd, void *buf, size_t count) {
- int ret = syscall(SYS_read, fd, buf, count);
+ ssize_t ret = syscall(SYS_read, (long)fd, (long)buf, (long)count, 0, 0, 0);
if (ret < 0) {
errno = -ret;
diff --git a/realloc.c b/realloc.c
@@ -5,14 +5,6 @@
#include "libc.h"
-struct block_header {
- size_t size;
- int is_free;
- struct block_header *next;
-};
-
-typedef struct block_header block_header_t;
-
void* realloc(void *ptr, size_t size) {
if (ptr == NULL) {
return malloc(size);
@@ -23,9 +15,10 @@ void* realloc(void *ptr, size_t size) {
}
block_header_t *header = (block_header_t*)ptr - 1;
- size_t old_size = header->size - sizeof(block_header_t);
+ size_t old_size = header->requested_size;
if (old_size >= size) {
+ header->requested_size = size;
return ptr;
}
diff --git a/rmdir.c b/rmdir.c
@@ -6,7 +6,7 @@
#include "libc.h"
int rmdir(const char *path) {
- int ret = syscall(SYS_rmdir, path);
+ int ret = syscall(SYS_rmdir, (long)path, 0, 0, 0, 0, 0);
if (ret < 0) {
errno = -ret;
diff --git a/stat.c b/stat.c
@@ -0,0 +1,17 @@
+/*
+ * stat.c - stat system call
+ * Copyright (C) 2026. All rights reserved.
+ */
+
+#include "libc.h"
+
+int stat(const char *pathname, struct stat *statbuf) {
+ int ret = syscall(SYS_stat, (long)pathname, (long)statbuf, 0, 0, 0, 0);
+
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+
+ return ret;
+}
diff --git a/strchr.c b/strchr.c
@@ -6,16 +6,18 @@
#include "libc.h"
char *strchr(const char *s, int c) {
- char chr = (char)c;
+ unsigned char chr = (unsigned char)c;
while (*s != '\0') {
- if (*s == chr)
+ if ((unsigned char)*s == chr) {
return (char *)s;
+ }
s++;
}
- if (chr == '\0')
+ if (chr == '\0') {
return (char *)s;
+ }
return NULL;
}
diff --git a/syscall.c b/syscall.c
@@ -3,12 +3,11 @@
* Copyright (C) 2026. All rights reserved.
*/
-#include <stdarg.h>
#include "libc.h"
static inline long call(long n, long a1, long a2, long a3, long a4, long a5, long a6)
{
- unsigned long ret;
+ long ret;
register long r10 __asm__("r10") = a4;
register long r8 __asm__("r8") = a5;
@@ -20,15 +19,6 @@ static inline long call(long n, long a1, long a2, long a3, long a4, long a5, lon
return ret;
}
-long syscall(long num, ...) {
- va_list valist;
- long args[6] = {0, 0, 0, 0, 0, 0};
-
- va_start(valist, num);
- for (int i = 0; i < 6; i++) {
- args[i] = va_arg(valist, long);
- }
- va_end(valist);
-
- return call(num, args[0], args[1], args[2], args[3], args[4], args[5]);
+long syscall(long num, long a1, long a2, long a3, long a4, long a5, long a6) {
+ return call(num, a1, a2, a3, a4, a5, a6);
}
diff --git a/unlink.c b/unlink.c
@@ -6,7 +6,7 @@
#include "libc.h"
int unlink(const char *path) {
- int ret = syscall(SYS_unlink, path);
+ int ret = syscall(SYS_unlink, (long)path, 0, 0, 0, 0, 0);
if (ret < 0) {
errno = -ret;
diff --git a/utime.c b/utime.c
@@ -6,7 +6,7 @@
#include "libc.h"
int utime(const char *path, const struct utimbuf *times) {
- int ret = syscall(SYS_utime, path, times);
+ int ret = syscall(SYS_utime, (long)path, (long)times, 0, 0, 0, 0);
if (ret < 0) {
errno = -ret;
return -1;
diff --git a/waitpid.c b/waitpid.c
@@ -6,7 +6,7 @@
#include "libc.h"
int waitpid(int pid, int *status, int options) {
- int ret = syscall(SYS_wait4, pid, status, options, NULL);
+ int ret = syscall(SYS_wait4, (long)pid, (long)status, (long)options, 0, 0, 0);
if (ret < 0) {
errno = -ret;
diff --git a/write.c b/write.c
@@ -6,7 +6,7 @@
#include "libc.h"
ssize_t write(int fd, const void *buf, size_t count) {
- int ret = syscall(SYS_write, fd, buf, count);
+ ssize_t ret = syscall(SYS_write, (long)fd, (long)buf, (long)count, 0, 0, 0);
if (ret < 0) {
errno = -ret;