Initial commit after splitting userspace from kernel tree
This commit is contained in:
commit
638edb5166
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
kernel-hdr
|
||||||
|
build
|
96
Makefile
Normal file
96
Makefile
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
O?=build
|
||||||
|
STAGE=$(O)/stage
|
||||||
|
KERNEL_HDRS?=kernel-hdr
|
||||||
|
|
||||||
|
CC=$(CROSS_COMPILE)gcc
|
||||||
|
|
||||||
|
DIRS=$(O) \
|
||||||
|
$(O)/libc \
|
||||||
|
$(STAGE)
|
||||||
|
HDRS=$(shell find $(S) -type f -name "*.h")
|
||||||
|
STAGE_BIN=$(STAGE)/init \
|
||||||
|
$(STAGE)/bin/hexd \
|
||||||
|
$(STAGE)/bin/ls \
|
||||||
|
$(STAGE)/bin/reboot
|
||||||
|
|
||||||
|
CFLAGS=-ffreestanding \
|
||||||
|
-nostdlib \
|
||||||
|
-mno-sse \
|
||||||
|
-mno-sse2 \
|
||||||
|
-Ilibc/include \
|
||||||
|
-ggdb \
|
||||||
|
-O0 \
|
||||||
|
-I$(KERNEL_HDRS)
|
||||||
|
|
||||||
|
usr_LDFLAGS=-nostdlib \
|
||||||
|
-lgcc \
|
||||||
|
-Tlibc/program.ld
|
||||||
|
usr_STATIC_LIBS=$(O)/libc.a
|
||||||
|
|
||||||
|
libc_CRTI=$(O)/libc/crti.o
|
||||||
|
libc_CRTN=$(O)/libc/crtn.o
|
||||||
|
libc_OBJS=$(O)/libc/crt0.o \
|
||||||
|
$(O)/libc/syscall.o \
|
||||||
|
$(O)/libc/vsnprintf.o \
|
||||||
|
$(O)/libc/printf.o \
|
||||||
|
$(O)/libc/string.o \
|
||||||
|
$(O)/libc/errno.o \
|
||||||
|
$(O)/libc/stdio.o \
|
||||||
|
$(O)/libc/init.o \
|
||||||
|
$(O)/libc/malloc.o \
|
||||||
|
$(O)/libc/dirent.o \
|
||||||
|
$(O)/libc/signal.o \
|
||||||
|
$(O)/libc/global.o \
|
||||||
|
$(O)/libc/time.o
|
||||||
|
|
||||||
|
sys_CRTBEGIN=$(shell $(CC) $(CFLAGS) -print-file-name=crtbegin.o)
|
||||||
|
sys_CRTEND=$(shell $(CC) $(CFLAGS) -print-file-name=crtend.o)
|
||||||
|
|
||||||
|
all: mkdirs $(O)/initrd.img
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(O)
|
||||||
|
|
||||||
|
$(O)/initrd.img: mkstage-etc $(STAGE_BIN)
|
||||||
|
cd $(STAGE) && tar czf $(abspath $@) *
|
||||||
|
|
||||||
|
mkdirs:
|
||||||
|
mkdir -p $(DIRS)
|
||||||
|
|
||||||
|
mkstage-etc:
|
||||||
|
mkdir -p $(STAGE)/dev $(STAGE)/mnt $(STAGE)/bin
|
||||||
|
cp -r etc $(STAGE)
|
||||||
|
|
||||||
|
# Application building
|
||||||
|
$(STAGE)/init: init.c $(libc_CRTI) $(libc_CRTN) $(O)/libc.a
|
||||||
|
@printf " CC\t%s\n" $(@:$(STAGE)/%=/%)
|
||||||
|
@$(CC) -o $@ $(CFLAGS) $(usr_LDFLAGS) \
|
||||||
|
$(libc_CRTI) \
|
||||||
|
$(sys_CRTBEGIN) \
|
||||||
|
init.c \
|
||||||
|
$(sys_CRTEND) \
|
||||||
|
$(libc_CRTN) \
|
||||||
|
$(usr_STATIC_LIBS)
|
||||||
|
|
||||||
|
$(STAGE)/bin/%: core/bin/%.c $(libc_CRTI) $(libc_CRTN) $(O)/libc.a
|
||||||
|
@printf " CC\t%s\n" $(@:$(STAGE)/%=/%)
|
||||||
|
@$(CC) -o $@ $(CFLAGS) $(usr_LDFLAGS) \
|
||||||
|
$(libc_CRTI) \
|
||||||
|
$(sys_CRTBEGIN) \
|
||||||
|
$< \
|
||||||
|
$(sys_CRTEND) \
|
||||||
|
$(libc_CRTN) \
|
||||||
|
$(usr_STATIC_LIBS)
|
||||||
|
|
||||||
|
# libc building
|
||||||
|
$(O)/libc.a: $(libc_OBJS)
|
||||||
|
@printf " AR\t%s\n" $(@:$(O)/%=%)
|
||||||
|
@$(AR) rcs $@ $(libc_OBJS)
|
||||||
|
|
||||||
|
$(O)/libc/%.o: libc/%.c $(HDRS)
|
||||||
|
@printf " CC\t%s\n" $(@:$(O)/%=%)
|
||||||
|
@$(CC) -c -o $@ $(CFLAGS) $<
|
||||||
|
|
||||||
|
$(O)/libc/%.o: libc/%.S
|
||||||
|
@printf " AS\t%s\n" $(@:$(O)/%=%)
|
||||||
|
@$(CC) -c -o $@ $(CFLAGS) $<
|
3
README.md
Normal file
3
README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Make a symlink to kernel headers (<kernel git tree>/include) directory named kernel-hdr or
|
||||||
|
specify direct path using `KERNEL_HDRS` env variable, specify proper ``CROSS_COMPILE` and run
|
||||||
|
make
|
95
core/bin/hexd.c
Normal file
95
core/bin/hexd.c
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#include <sys/fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define LINE_LENGTH 16
|
||||||
|
|
||||||
|
static void line_print(size_t off, const char *line, size_t len) {
|
||||||
|
printf("%08x: ", off);
|
||||||
|
for (size_t i = 0; i < LINE_LENGTH; ++i) {
|
||||||
|
// XXX: This is needed because I didn't implement h/hh modifiers in printf
|
||||||
|
uint64_t byte = (uint64_t) line[i] & 0xFF;
|
||||||
|
if (i < len) {
|
||||||
|
printf("%02x", byte);
|
||||||
|
} else {
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
if (i % 2) {
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("| ");
|
||||||
|
for (size_t i = 0; i < len; ++i) {
|
||||||
|
// TODO: isprint?
|
||||||
|
if (line[i] >= ' ') {
|
||||||
|
printf("%c", line[i]);
|
||||||
|
} else {
|
||||||
|
printf(".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
int fd;
|
||||||
|
const char *path;
|
||||||
|
char buf[512];
|
||||||
|
char line[LINE_LENGTH];
|
||||||
|
ssize_t bread;
|
||||||
|
size_t offset;
|
||||||
|
size_t linel;
|
||||||
|
size_t n_full_zero;
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
printf("wrong\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
path = argv[1];
|
||||||
|
printf("open file %s\n", path);
|
||||||
|
|
||||||
|
if ((fd = open(path, O_RDONLY, 0)) < 0) {
|
||||||
|
perror(path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = 0;
|
||||||
|
linel = 0;
|
||||||
|
n_full_zero = 0;
|
||||||
|
while ((bread = read(fd, buf, sizeof(buf))) > 0) {
|
||||||
|
for (size_t i = 0; i < bread; ++i) {
|
||||||
|
line[linel++] = buf[i];
|
||||||
|
if (linel == LINE_LENGTH) {
|
||||||
|
// Check if the line is all zeros
|
||||||
|
int all_zeros = 1;
|
||||||
|
for (size_t j = 0; j < LINE_LENGTH; ++j) {
|
||||||
|
if (line[j]) {
|
||||||
|
all_zeros = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (all_zeros) {
|
||||||
|
++n_full_zero;
|
||||||
|
} else {
|
||||||
|
n_full_zero = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n_full_zero < 3) {
|
||||||
|
line_print(offset, line, linel);
|
||||||
|
} else if (n_full_zero == 3) {
|
||||||
|
printf(" ... \n");
|
||||||
|
}
|
||||||
|
offset += LINE_LENGTH;
|
||||||
|
linel = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (linel) {
|
||||||
|
line_print(offset, line, linel);
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
136
core/bin/ls.c
Normal file
136
core/bin/ls.c
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
#include <sys/stat.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define LS_COLOR (1 << 0)
|
||||||
|
#define LS_DETAIL (1 << 1)
|
||||||
|
|
||||||
|
#define COLOR_DIR "\033[36m"
|
||||||
|
#define COLOR_DEV "\033[33m"
|
||||||
|
#define COLOR_UNKNOWN "\033[43m"
|
||||||
|
|
||||||
|
#define COLOR_RESET "\033[0m"
|
||||||
|
|
||||||
|
static int ls_dir(const char *path, int flags) {
|
||||||
|
int res;
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent *ent;
|
||||||
|
struct stat ent_stat;
|
||||||
|
char ent_path[512];
|
||||||
|
char t;
|
||||||
|
|
||||||
|
if (!(dir = opendir(path))) {
|
||||||
|
perror(path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((ent = readdir(dir))) {
|
||||||
|
if (ent->d_name[0] != '.') {
|
||||||
|
if (flags & LS_DETAIL) {
|
||||||
|
snprintf(ent_path, sizeof(ent_path), "%s/%s",
|
||||||
|
strcmp(path, "") ? path : ".", ent->d_name);
|
||||||
|
if (stat(ent_path, &ent_stat) != 0) {
|
||||||
|
printf("?????????? ? ? ? ");
|
||||||
|
} else {
|
||||||
|
switch (ent_stat.st_mode & S_IFMT) {
|
||||||
|
case S_IFDIR:
|
||||||
|
t = 'd';
|
||||||
|
break;
|
||||||
|
case S_IFREG:
|
||||||
|
t = '-';
|
||||||
|
break;
|
||||||
|
case S_IFBLK:
|
||||||
|
t = 'b';
|
||||||
|
break;
|
||||||
|
case S_IFCHR:
|
||||||
|
t = 'c';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
t = '?';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%c%c%c%c%c%c%c%c%c%c ",
|
||||||
|
t,
|
||||||
|
(ent_stat.st_mode & S_IRUSR) ? 'r' : '-',
|
||||||
|
(ent_stat.st_mode & S_IWUSR) ? 'w' : '-',
|
||||||
|
(ent_stat.st_mode & S_IXUSR) ? 'x' : '-',
|
||||||
|
(ent_stat.st_mode & S_IRGRP) ? 'r' : '-',
|
||||||
|
(ent_stat.st_mode & S_IWGRP) ? 'w' : '-',
|
||||||
|
(ent_stat.st_mode & S_IXGRP) ? 'x' : '-',
|
||||||
|
(ent_stat.st_mode & S_IROTH) ? 'r' : '-',
|
||||||
|
(ent_stat.st_mode & S_IWOTH) ? 'w' : '-',
|
||||||
|
(ent_stat.st_mode & S_IXOTH) ? 'x' : '-');
|
||||||
|
|
||||||
|
printf("%4u %4u %8u ",
|
||||||
|
ent_stat.st_gid,
|
||||||
|
ent_stat.st_uid,
|
||||||
|
ent_stat.st_blocks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & LS_COLOR) {
|
||||||
|
switch (ent->d_type) {
|
||||||
|
case DT_REG:
|
||||||
|
break;
|
||||||
|
case DT_BLK:
|
||||||
|
case DT_CHR:
|
||||||
|
write(STDOUT_FILENO, COLOR_DEV, 5);
|
||||||
|
break;
|
||||||
|
case DT_DIR:
|
||||||
|
write(STDOUT_FILENO, COLOR_DIR, 5);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
write(STDOUT_FILENO, COLOR_UNKNOWN, 5);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write(STDOUT_FILENO, ent->d_name, strlen(ent->d_name));
|
||||||
|
if (flags & LS_COLOR) {
|
||||||
|
write(STDOUT_FILENO, COLOR_RESET, 4);
|
||||||
|
}
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
// Basic getopt-like features
|
||||||
|
int first = -1;
|
||||||
|
int flags = 0;
|
||||||
|
|
||||||
|
for (int i = 1; i < argc; ++i) {
|
||||||
|
if (argv[i][0] != '-') {
|
||||||
|
first = i;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (!strcmp(argv[i], "-c")) {
|
||||||
|
flags |= LS_COLOR;
|
||||||
|
} else if (!strcmp(argv[i], "-d")) {
|
||||||
|
flags |= LS_DETAIL;
|
||||||
|
} else {
|
||||||
|
printf("Unknown option: %s\n", argv[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first == -1) {
|
||||||
|
ls_dir("", flags);
|
||||||
|
} else {
|
||||||
|
for (int i = first; i < argc; ++i) {
|
||||||
|
if (first != argc - 1) {
|
||||||
|
printf("%s:\n", argv[i]);
|
||||||
|
}
|
||||||
|
ls_dir(argv[i], flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
33
core/bin/reboot.c
Normal file
33
core/bin/reboot.c
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
const char *arg = NULL;
|
||||||
|
|
||||||
|
if (argc == 2) {
|
||||||
|
arg = argv[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
int res;
|
||||||
|
unsigned int cmd = YGG_REBOOT_RESTART;
|
||||||
|
|
||||||
|
if (arg) {
|
||||||
|
if (!strcmp(arg, "-s")) {
|
||||||
|
cmd = YGG_REBOOT_POWER_OFF;
|
||||||
|
} else if (!strcmp(arg, "-h")) {
|
||||||
|
cmd = YGG_REBOOT_HALT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((res = reboot(YGG_REBOOT_MAGIC1, YGG_REBOOT_MAGIC2, cmd, NULL)) < 0) {
|
||||||
|
perror("reboot()");
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
usleep(1000000);
|
||||||
|
}
|
||||||
|
}
|
1
etc/file.txt
Normal file
1
etc/file.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
This file is inside the initrd.
|
410
init.c
Normal file
410
init.c
Normal file
@ -0,0 +1,410 @@
|
|||||||
|
#include <sys/fcntl.h>
|
||||||
|
#include <sys/reboot.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
// Cursor helpers
|
||||||
|
|
||||||
|
#define curs_save() \
|
||||||
|
write(STDOUT_FILENO, "\033[s", 3)
|
||||||
|
#define curs_unsave() \
|
||||||
|
write(STDOUT_FILENO, "\033[u", 3)
|
||||||
|
#define curs_set(row, col) \
|
||||||
|
printf("\033[%d;%df", row, col)
|
||||||
|
#define clear() \
|
||||||
|
write(STDOUT_FILENO, "\033[2J", 4)
|
||||||
|
|
||||||
|
#define BOX_ANGLE_UL "\332"
|
||||||
|
#define BOX_ANGLE_UR "\277"
|
||||||
|
#define BOX_ANGLE_LL "\300"
|
||||||
|
#define BOX_ANGLE_LR "\331"
|
||||||
|
#define BOX_HOR "\304"
|
||||||
|
#define BOX_VERT "\263"
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
extern __attribute__((noreturn)) void abort(void);
|
||||||
|
|
||||||
|
#define assert(x) \
|
||||||
|
if (!(x)) abort()
|
||||||
|
|
||||||
|
struct builtin {
|
||||||
|
const char *name;
|
||||||
|
const char *desc;
|
||||||
|
int (*run) (const char *arg);
|
||||||
|
};
|
||||||
|
|
||||||
|
static int b_cd(const char *path);
|
||||||
|
static int b_pwd(const char *_);
|
||||||
|
static int b_cat(const char *path);
|
||||||
|
static int b_curs(const char *arg);
|
||||||
|
static int b_sleep(const char *arg);
|
||||||
|
static int b_help(const char *arg);
|
||||||
|
static int b_clear(const char *arg);
|
||||||
|
|
||||||
|
static struct builtin builtins[] = {
|
||||||
|
{
|
||||||
|
"cd",
|
||||||
|
"Change working directory",
|
||||||
|
b_cd,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pwd",
|
||||||
|
"Print working directory",
|
||||||
|
b_pwd,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cat",
|
||||||
|
"Print file contents" /* Concatenate files */,
|
||||||
|
b_cat
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sleep",
|
||||||
|
"Sleep N seconds",
|
||||||
|
b_sleep
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"clear",
|
||||||
|
"Clear terminal",
|
||||||
|
b_clear,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"help",
|
||||||
|
"Please help me",
|
||||||
|
b_help
|
||||||
|
},
|
||||||
|
{ NULL, NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static int b_cd(const char *arg) {
|
||||||
|
int res;
|
||||||
|
if (!arg) {
|
||||||
|
arg = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((res = chdir(arg)) < 0) {
|
||||||
|
perror(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int b_pwd(const char *arg) {
|
||||||
|
char buf[512];
|
||||||
|
if (!getcwd(buf, sizeof(buf))) {
|
||||||
|
perror("getcwd()");
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
puts(buf);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int b_cat(const char *arg) {
|
||||||
|
char buf[512];
|
||||||
|
int fd;
|
||||||
|
ssize_t bread;
|
||||||
|
|
||||||
|
if (!arg) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((fd = open(arg, O_RDONLY, 0)) < 0) {
|
||||||
|
perror(arg);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((bread = read(fd, buf, sizeof(buf))) > 0) {
|
||||||
|
write(STDOUT_FILENO, buf, bread);
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int b_curs(const char *arg) {
|
||||||
|
char c;
|
||||||
|
|
||||||
|
size_t w = 60;
|
||||||
|
size_t h = 20;
|
||||||
|
size_t off_y = (25 - h) / 2 + 1;
|
||||||
|
size_t off_x = (80 - w) / 2;
|
||||||
|
|
||||||
|
const char *lines[18] = {
|
||||||
|
NULL,
|
||||||
|
"Demo something",
|
||||||
|
NULL,
|
||||||
|
"Slow as hell"
|
||||||
|
};
|
||||||
|
|
||||||
|
clear();
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
printf("\033[47;30m");
|
||||||
|
|
||||||
|
curs_set(off_y, off_x);
|
||||||
|
printf(BOX_ANGLE_UL);
|
||||||
|
for (size_t i = 0; i < w; ++i) {
|
||||||
|
printf(BOX_HOR);
|
||||||
|
}
|
||||||
|
printf(BOX_ANGLE_UR);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < h - 2; ++i) {
|
||||||
|
curs_set(off_y + 1 + i, off_x);
|
||||||
|
printf(BOX_VERT);
|
||||||
|
for (size_t j = 0; j < w; ++j) {
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
if (lines[i]) {
|
||||||
|
curs_set(off_y + 1 + i, off_x + (w - strlen(lines[i])) / 2);
|
||||||
|
printf("%s", lines[i]);
|
||||||
|
}
|
||||||
|
curs_set(off_y + 1 + i, off_x + w + 1);
|
||||||
|
printf(BOX_VERT);
|
||||||
|
}
|
||||||
|
|
||||||
|
curs_set(off_y + h - 3, off_x + (w - 8) / 2);
|
||||||
|
printf("\033[0m\033[7m[ OK ]\033[47;30m");
|
||||||
|
curs_set(off_y + h - 1, off_x);
|
||||||
|
printf(BOX_ANGLE_LL);
|
||||||
|
for (size_t i = 0; i < w; ++i) {
|
||||||
|
printf(BOX_HOR);
|
||||||
|
}
|
||||||
|
printf(BOX_ANGLE_LR);
|
||||||
|
|
||||||
|
printf("\033[0m");
|
||||||
|
|
||||||
|
curs_set(1, 1);
|
||||||
|
|
||||||
|
if (read(STDIN_FILENO, &c, 1) < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 'q' || c == '\n') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
curs_set(1, 1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int b_sleep(const char *arg) {
|
||||||
|
if (!arg) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int seconds = 0;
|
||||||
|
while (*arg) {
|
||||||
|
seconds *= 10;
|
||||||
|
seconds += *arg - '0';
|
||||||
|
++arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct timespec ts = { seconds, 0 };
|
||||||
|
if ((seconds = nanosleep(&ts, NULL))) {
|
||||||
|
perror("nanosleep()");
|
||||||
|
return seconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int b_clear(const char *arg) {
|
||||||
|
clear();
|
||||||
|
curs_set(1, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int b_help(const char *arg) {
|
||||||
|
if (arg) {
|
||||||
|
// Describe a specific command
|
||||||
|
for (size_t i = 0; builtins[i].run; ++i) {
|
||||||
|
if (!strcmp(arg, builtins[i].name)) {
|
||||||
|
printf("%s: %s\n", builtins[i].name, builtins[i].desc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%s: Unknown command\n", arg);
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
for (size_t i = 0; builtins[i].run; ++i) {
|
||||||
|
printf("%s: %s\n", builtins[i].name, builtins[i].desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prompt(void) {
|
||||||
|
char cwd[512];
|
||||||
|
if (!getcwd(cwd, sizeof(cwd))) {
|
||||||
|
cwd[0] = '?';
|
||||||
|
cwd[1] = 0;
|
||||||
|
}
|
||||||
|
printf("\033[36mygg\033[0m %s > ", cwd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmd_subproc_exec(const char *abs_path, const char *cmd, const char *e) {
|
||||||
|
// Maximum of 8 arguments 64 chars each (63)
|
||||||
|
// Split input argument into pieces by space
|
||||||
|
char args[64 * 8] = {0};
|
||||||
|
const char *p = e;
|
||||||
|
const char *t = NULL;
|
||||||
|
size_t argc = 0;
|
||||||
|
while (p) {
|
||||||
|
t = strchr(p, ' ');
|
||||||
|
if (!t) {
|
||||||
|
// Last argument
|
||||||
|
assert(strlen(p) < 64);
|
||||||
|
strcpy(&args[argc++ * 64], p);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
assert(t - p < 64);
|
||||||
|
strncpy(&args[argc * 64], p, t - p);
|
||||||
|
args[(argc++ * 64) + (t - p)] = 0;
|
||||||
|
p = t + 1;
|
||||||
|
while (*p == ' ') {
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
if (!*p) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill arg pointer array
|
||||||
|
const char *argp[10] = { cmd };
|
||||||
|
for (size_t i = 0; i < argc; ++i) {
|
||||||
|
argp[i + 1] = &args[i * 64];
|
||||||
|
}
|
||||||
|
argp[argc + 1] = NULL;
|
||||||
|
|
||||||
|
int pid = fork();
|
||||||
|
int res;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
switch (pid) {
|
||||||
|
case -1:
|
||||||
|
perror("fork()");
|
||||||
|
return -1;
|
||||||
|
case 0:
|
||||||
|
if (execve(abs_path, argp, NULL) != 0) {
|
||||||
|
perror("execve()");
|
||||||
|
}
|
||||||
|
exit(-1);
|
||||||
|
default:
|
||||||
|
if (waitpid(pid, &status) != 0) {
|
||||||
|
perror("waitpid()");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmd_exec(const char *line) {
|
||||||
|
char cmd[64];
|
||||||
|
const char *e = strchr(line, ' ');
|
||||||
|
|
||||||
|
if (!e) {
|
||||||
|
assert(strlen(line) < 64);
|
||||||
|
strcpy(cmd, line);
|
||||||
|
} else {
|
||||||
|
assert(e - line < 64);
|
||||||
|
strncpy(cmd, line, e - line);
|
||||||
|
cmd[e - line] = 0;
|
||||||
|
++e;
|
||||||
|
while (*e == ' ') {
|
||||||
|
++e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e && !*e) {
|
||||||
|
e = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; builtins[i].run; ++i) {
|
||||||
|
if (!strcmp(cmd, builtins[i].name)) {
|
||||||
|
return builtins[i].run(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If command starts with ./ or /, try to execute it
|
||||||
|
if (((cmd[0] == '.' && cmd[1] == '/') || cmd[0] == '/') && access(cmd, X_OK) == 0) {
|
||||||
|
return cmd_subproc_exec(cmd, cmd, e);
|
||||||
|
}
|
||||||
|
// Try to execute binary from /bin
|
||||||
|
char path_buf[512];
|
||||||
|
snprintf(path_buf, sizeof(path_buf), "/bin/%s", cmd);
|
||||||
|
if (access(path_buf, X_OK) == 0) {
|
||||||
|
return cmd_subproc_exec(path_buf, cmd, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%s: Unknown command\n", cmd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
if (getpid() != 1) {
|
||||||
|
printf("Won't work if PID is not 1\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
char linebuf[512];
|
||||||
|
char c;
|
||||||
|
size_t l = 0;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
prompt();
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if ((res = fork()) < 0) {
|
||||||
|
perror("fork()");
|
||||||
|
return -1;
|
||||||
|
} else if (res == 0) {
|
||||||
|
if (execve("/time", NULL, NULL) != 0) {
|
||||||
|
perror("execve()");
|
||||||
|
}
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (read(STDIN_FILENO, &c, 1) < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '\b') {
|
||||||
|
if (l) {
|
||||||
|
linebuf[--l] = 0;
|
||||||
|
printf("\033[D \033[D");
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c == '\n') {
|
||||||
|
write(STDOUT_FILENO, &c, 1);
|
||||||
|
linebuf[l] = 0;
|
||||||
|
|
||||||
|
if (!strcmp(linebuf, "exit")) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
l = 0;
|
||||||
|
if ((res = cmd_exec(linebuf)) != 0) {
|
||||||
|
printf("\033[31m= %d\033[0m\n", res);
|
||||||
|
}
|
||||||
|
prompt();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
linebuf[l++] = c;
|
||||||
|
write(STDOUT_FILENO, &c, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
25
libc/crt0.S
Normal file
25
libc/crt0.S
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
.section .text
|
||||||
|
.global _start
|
||||||
|
.type _start, %function
|
||||||
|
// Arguments:
|
||||||
|
// %rdi - argp
|
||||||
|
_start:
|
||||||
|
movq $0, %rbp
|
||||||
|
// For callee linkage
|
||||||
|
pushq %rbp
|
||||||
|
pushq %rbp
|
||||||
|
movq %rsp, %rbp
|
||||||
|
|
||||||
|
push %rdi
|
||||||
|
call __libc_init
|
||||||
|
|
||||||
|
call _init
|
||||||
|
|
||||||
|
mov __libc_argc, %rdi
|
||||||
|
pop %rsi
|
||||||
|
|
||||||
|
// exit(main(argc, argv))
|
||||||
|
call main
|
||||||
|
movq %rax, %rdi
|
||||||
|
call exit
|
||||||
|
.size _start, . - _start
|
16
libc/crti.S
Normal file
16
libc/crti.S
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/* x86_64 crti.s */
|
||||||
|
.section .init
|
||||||
|
.global _init
|
||||||
|
.type _init, @function
|
||||||
|
_init:
|
||||||
|
push %rbp
|
||||||
|
movq %rsp, %rbp
|
||||||
|
/* gcc will nicely put the contents of crtbegin.o's .init section here. */
|
||||||
|
|
||||||
|
.section .fini
|
||||||
|
.global _fini
|
||||||
|
.type _fini, @function
|
||||||
|
_fini:
|
||||||
|
push %rbp
|
||||||
|
movq %rsp, %rbp
|
||||||
|
/* gcc will nicely put the contents of crtbegin.o's .fini section here. */
|
10
libc/crtn.S
Normal file
10
libc/crtn.S
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/* x86_64 crtn.s */
|
||||||
|
.section .init
|
||||||
|
/* gcc will nicely put the contents of crtend.o's .init section here. */
|
||||||
|
popq %rbp
|
||||||
|
ret
|
||||||
|
|
||||||
|
.section .fini
|
||||||
|
/* gcc will nicely put the contents of crtend.o's .fini section here. */
|
||||||
|
popq %rbp
|
||||||
|
ret
|
57
libc/dirent.c
Normal file
57
libc/dirent.c
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#include "dirent.h"
|
||||||
|
#include "bits/syscall.h"
|
||||||
|
#include <sys/fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
extern void *malloc(size_t count);
|
||||||
|
extern void free(void *p);
|
||||||
|
|
||||||
|
struct DIR_private {
|
||||||
|
int fd;
|
||||||
|
struct dirent buf;
|
||||||
|
};
|
||||||
|
|
||||||
|
DIR *opendir(const char *path) {
|
||||||
|
int fd;
|
||||||
|
DIR *res;
|
||||||
|
|
||||||
|
if (!(res = malloc(sizeof(struct DIR_private)))) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ((fd = open(path, O_DIRECTORY | O_RDONLY, 0)) < 0) {
|
||||||
|
fd = errno;
|
||||||
|
free(res);
|
||||||
|
errno = fd;
|
||||||
|
// errno is set
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
res->fd = fd;
|
||||||
|
memset(&res->buf, 0, sizeof(res->buf));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void closedir(DIR *dirp) {
|
||||||
|
if (!dirp) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
close(dirp->fd);
|
||||||
|
free(dirp);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dirent *readdir(DIR *dirp) {
|
||||||
|
ssize_t res;
|
||||||
|
if (!dirp) {
|
||||||
|
errno = EBADF;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if ((res = sys_readdir(dirp->fd, &dirp->buf)) <= 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return &dirp->buf;
|
||||||
|
}
|
57
libc/errno.c
Normal file
57
libc/errno.c
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
static const char *err_strings0[35] = {
|
||||||
|
"Success",
|
||||||
|
"Operation not permitted",
|
||||||
|
"No such file or directory",
|
||||||
|
"No such process",
|
||||||
|
"Interrupted system call",
|
||||||
|
"I/O error",
|
||||||
|
"No such device or address",
|
||||||
|
"Argument list too long",
|
||||||
|
"Exec format error",
|
||||||
|
"Bad file number",
|
||||||
|
"No child processes",
|
||||||
|
"Try again",
|
||||||
|
"Out of memory",
|
||||||
|
"Permission denied",
|
||||||
|
"Bad address",
|
||||||
|
"Block device required",
|
||||||
|
"Device or resource busy",
|
||||||
|
"File exists",
|
||||||
|
"Cross-device link",
|
||||||
|
"No such device",
|
||||||
|
"Not a directory",
|
||||||
|
"Is a directory",
|
||||||
|
"Invalid argument",
|
||||||
|
"File table overflow",
|
||||||
|
"Too many open files",
|
||||||
|
"Not a typewriter",
|
||||||
|
"Text file busy",
|
||||||
|
"File too large",
|
||||||
|
"No space left on device",
|
||||||
|
"Illegal seek",
|
||||||
|
"Read-only file system",
|
||||||
|
"Too many links",
|
||||||
|
"Broken pipe",
|
||||||
|
"Math argument out of domain of func",
|
||||||
|
"Math result not representable"
|
||||||
|
};
|
||||||
|
|
||||||
|
int errno;
|
||||||
|
|
||||||
|
char *strerror(int n) {
|
||||||
|
if (n >= 0 && n <= 34) {
|
||||||
|
return (char *) err_strings0[n];
|
||||||
|
}
|
||||||
|
return (char *) "Unknown error";
|
||||||
|
}
|
||||||
|
|
||||||
|
void perror(const char *e) {
|
||||||
|
if (e && *e) {
|
||||||
|
printf("%s: %s\n", e, strerror(errno));
|
||||||
|
} else {
|
||||||
|
puts(strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
4
libc/global.c
Normal file
4
libc/global.c
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#include "bits/global.h"
|
||||||
|
|
||||||
|
void *__cur_brk;
|
||||||
|
uint64_t __libc_argc = 0;
|
5
libc/include/bits/global.h
Normal file
5
libc/include/bits/global.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
extern void *__cur_brk;
|
||||||
|
extern uint64_t __libc_argc;
|
7
libc/include/bits/printf.h
Normal file
7
libc/include/bits/printf.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
int printf(const char *fmt, ...);
|
||||||
|
int snprintf(char *buf, size_t size, const char *fmt, ...);
|
||||||
|
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
|
30
libc/include/bits/syscall.h
Normal file
30
libc/include/bits/syscall.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <sys/fs/dirent.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
ssize_t read(int fd, void *buf, size_t count);
|
||||||
|
ssize_t write(int fd, const void *buf, size_t count);
|
||||||
|
int open(const char *filename, int flags, int mode);
|
||||||
|
void close(int fd);
|
||||||
|
int stat(const char *filename, struct stat *st);
|
||||||
|
void *mmap(void *addr, size_t len, int prot, int flags, int fd, uintptr_t offset);
|
||||||
|
int fork(void);
|
||||||
|
int execve(const char *filename, const char *const argv[], const char *const envp[]);
|
||||||
|
ssize_t sys_readdir(int fd, struct dirent *entp);
|
||||||
|
int kill(int pid, int signum);
|
||||||
|
void __kernel_signal(uintptr_t handler);
|
||||||
|
__attribute__((noreturn)) void __kernel_sigret(void);
|
||||||
|
int getpid(void);
|
||||||
|
int chdir(const char *filename);
|
||||||
|
char *getcwd(char *buf, size_t size);
|
||||||
|
int nanosleep(const struct timespec *req, struct timespec *rem);
|
||||||
|
int openpty(int *amaster, int *aslave);
|
||||||
|
int gettimeofday(struct timeval *tv, struct timezone *tz);
|
||||||
|
int reboot(int magic1, int magic2, unsigned int cmd, void *arg);
|
||||||
|
int access(const char *filename, int mode);
|
||||||
|
int waitpid(int pid, int *status);
|
||||||
|
|
||||||
|
__attribute__((noreturn)) void exit(int code);
|
8
libc/include/dirent.h
Normal file
8
libc/include/dirent.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <sys/fs/dirent.h>
|
||||||
|
|
||||||
|
typedef struct DIR_private DIR;
|
||||||
|
|
||||||
|
DIR *opendir(const char *path);
|
||||||
|
void closedir(DIR *dirp);
|
||||||
|
struct dirent *readdir(DIR *dirp);
|
7
libc/include/errno.h
Normal file
7
libc/include/errno.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <sys/errno.h>
|
||||||
|
|
||||||
|
extern int errno;
|
||||||
|
|
||||||
|
char *strerror(int errnum);
|
||||||
|
void perror(const char *s);
|
8
libc/include/signal.h
Normal file
8
libc/include/signal.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <sys/signum.h>
|
||||||
|
|
||||||
|
typedef void (*sighandler_t) (int);
|
||||||
|
|
||||||
|
sighandler_t signal(int signum, sighandler_t handler);
|
||||||
|
|
||||||
|
int raise(int signum);
|
6
libc/include/stdio.h
Normal file
6
libc/include/stdio.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
int puts(const char *s);
|
||||||
|
int putchar(int c);
|
||||||
|
|
||||||
|
#include "bits/printf.h"
|
3
libc/include/stdlib.h
Normal file
3
libc/include/stdlib.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
void abort(void);
|
17
libc/include/string.h
Normal file
17
libc/include/string.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
void *memcpy(void *restrict dst, const void *restrict src, size_t cnt);
|
||||||
|
void *memmove(void *dst, const void *src, size_t cnt);
|
||||||
|
void *memset(void *dst, int v, size_t count);
|
||||||
|
int memcmp(const void *a, const void *b, size_t count);
|
||||||
|
|
||||||
|
size_t strlen(const char *s);
|
||||||
|
int strncmp(const char *a, const char *b, size_t lim);
|
||||||
|
int strcmp(const char *a, const char *b);
|
||||||
|
char *strchr(const char *a, int c);
|
||||||
|
char *strrchr(const char *a, int c);
|
||||||
|
char *strcpy(char *dst, const char *src);
|
||||||
|
char *strncpy(char *dst, const char *src, size_t lim);
|
||||||
|
char *strcat(char *dst, const char *src);
|
||||||
|
char *strncat(char *dst, const char *src, size_t lim);
|
4
libc/include/time.h
Normal file
4
libc/include/time.h
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
int usleep(long us);
|
10
libc/include/unistd.h
Normal file
10
libc/include/unistd.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "bits/syscall.h"
|
||||||
|
#include <sys/reboot.h>
|
||||||
|
|
||||||
|
#define STDIN_FILENO 0
|
||||||
|
#define STDOUT_FILENO 1
|
||||||
|
#define STDERR_FILENO 2
|
||||||
|
|
||||||
|
void *sbrk(intptr_t diff);
|
||||||
|
int reboot(int magic1, int magic2, unsigned int cmd, void *arg);
|
18
libc/init.c
Normal file
18
libc/init.c
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#include <errno.h>
|
||||||
|
#include "bits/global.h"
|
||||||
|
|
||||||
|
extern char __heap_start;
|
||||||
|
extern void __libc_signal_init(void);
|
||||||
|
static const char *argp_dummy[] = { 0 };
|
||||||
|
|
||||||
|
void __libc_init(char **argp) {
|
||||||
|
__libc_signal_init();
|
||||||
|
__libc_argc = 0;
|
||||||
|
if (argp) {
|
||||||
|
while (argp[__libc_argc]) {
|
||||||
|
++__libc_argc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
__cur_brk = &__heap_start;
|
||||||
|
errno = 0;
|
||||||
|
}
|
15
libc/malloc.c
Normal file
15
libc/malloc.c
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include <unistd.h>
|
||||||
|
#include "bits/global.h"
|
||||||
|
|
||||||
|
// XXX: I'll implement a proper heap in the following commits
|
||||||
|
void *malloc(size_t count) {
|
||||||
|
void *p = __cur_brk;
|
||||||
|
if (sbrk(count) == p) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(void *ptr) {
|
||||||
|
|
||||||
|
}
|
25
libc/printf.c
Normal file
25
libc/printf.c
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#include "bits/printf.h"
|
||||||
|
#include <unistd.h>
|
||||||
|
#define PRINTF_BUFFER_SIZE 1024
|
||||||
|
|
||||||
|
int printf(const char *fmt, ...) {
|
||||||
|
char buf[PRINTF_BUFFER_SIZE];
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
int res = vsnprintf(buf, PRINTF_BUFFER_SIZE, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
// TODO: use libc's FILE * instead
|
||||||
|
return write(STDOUT_FILENO, buf, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
int snprintf(char *buf, size_t lim, const char *fmt, ...) {
|
||||||
|
va_list args;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
va_start(args, fmt);
|
||||||
|
res = vsnprintf(buf, PRINTF_BUFFER_SIZE, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
35
libc/program.ld
Normal file
35
libc/program.ld
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Userspace program linker script,
|
||||||
|
* partially derived from GCC's -static one
|
||||||
|
*/
|
||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
SECTIONS {
|
||||||
|
. = 0x400000;
|
||||||
|
|
||||||
|
.text : ALIGN(4K) {
|
||||||
|
KEEP (*(SORT_NONE(.init)))
|
||||||
|
*(.text)
|
||||||
|
KEEP (*(SORT_NONE(.fini)))
|
||||||
|
KEEP (*(SORT(.ctors.*)))
|
||||||
|
KEEP (*(.ctors))
|
||||||
|
KEEP (*(SORT(.dtors.*)))
|
||||||
|
KEEP (*(.dtors))
|
||||||
|
}
|
||||||
|
|
||||||
|
.rodata : {
|
||||||
|
*(.rodata)
|
||||||
|
*(.eh_frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
.data : ALIGN(4K) {
|
||||||
|
*(.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
.bss : ALIGN(4K) {
|
||||||
|
*(.bss)
|
||||||
|
}
|
||||||
|
|
||||||
|
__program_end = .;
|
||||||
|
__heap_start = .;
|
||||||
|
}
|
71
libc/signal.c
Normal file
71
libc/signal.c
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#include <bits/syscall.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
static sighandler_t signal_handlers[16] = {0};
|
||||||
|
|
||||||
|
void SIG_IGN(int signum) {
|
||||||
|
printf("Ignored: %d\n", signum);
|
||||||
|
|
||||||
|
while (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SIG_DFL(int signum) {
|
||||||
|
int pid = getpid();
|
||||||
|
|
||||||
|
switch (signum) {
|
||||||
|
case SIGKILL:
|
||||||
|
printf("%d: killed\n", pid);
|
||||||
|
break;
|
||||||
|
case SIGABRT:
|
||||||
|
printf("%d: aborted\n", pid);
|
||||||
|
break;
|
||||||
|
case SIGSEGV:
|
||||||
|
printf("%d: segmentation fault\n", pid);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("%d: signal %d\n", pid, signum);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __libc_signal_handle(int signum) {
|
||||||
|
if (signum >= 16) {
|
||||||
|
SIG_DFL(signum);
|
||||||
|
} else {
|
||||||
|
signal_handlers[signum](signum);
|
||||||
|
}
|
||||||
|
|
||||||
|
__kernel_sigret();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __libc_signal_init(void) {
|
||||||
|
for (size_t i = 0; i < 16; ++i) {
|
||||||
|
signal_handlers[i] = SIG_DFL;
|
||||||
|
}
|
||||||
|
|
||||||
|
__kernel_signal((uintptr_t) __libc_signal_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
sighandler_t signal(int signum, sighandler_t new_handler) {
|
||||||
|
sighandler_t old_handler;
|
||||||
|
|
||||||
|
if (signum >= 16) {
|
||||||
|
printf("Fuck\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
old_handler = signal_handlers[signum];
|
||||||
|
signal_handlers[signum] = new_handler;
|
||||||
|
return old_handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
int raise(int signum) {
|
||||||
|
return kill(getpid(), signum);
|
||||||
|
}
|
||||||
|
|
||||||
|
void abort(void) {
|
||||||
|
kill(getpid(), SIGABRT);
|
||||||
|
}
|
22
libc/stdio.c
Normal file
22
libc/stdio.c
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int puts(const char *s) {
|
||||||
|
size_t l = strlen(s);
|
||||||
|
int w = write(STDOUT_FILENO, s, l);
|
||||||
|
char c = '\n';
|
||||||
|
|
||||||
|
if (w == l) {
|
||||||
|
write(STDOUT_FILENO, &c, 1);
|
||||||
|
}
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
int putchar(int c) {
|
||||||
|
int res;
|
||||||
|
if ((res = write(STDOUT_FILENO, &c, 1)) < 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
167
libc/string.c
Normal file
167
libc/string.c
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
char *strcat(char *dst, const char *src) {
|
||||||
|
size_t l = strlen(dst);
|
||||||
|
strcpy(dst + l, src);
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *strncat(char *dst, const char *src, size_t lim) {
|
||||||
|
size_t l = strlen(dst);
|
||||||
|
if (l < lim) {
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
size_t r = lim - l;
|
||||||
|
strncpy(dst + l, src, r);
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t strlen(const char *a) {
|
||||||
|
size_t s = 0;
|
||||||
|
while (*a++) {
|
||||||
|
++s;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
int strncmp(const char *a, const char *b, size_t n) {
|
||||||
|
size_t c = 0;
|
||||||
|
for (; c < n && (*a || *b); ++c, ++a, ++b) {
|
||||||
|
if (*a != *b) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int strcmp(const char *a, const char *b) {
|
||||||
|
if (a == b) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (a == NULL || b == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for (; *a || *b; ++a, ++b) {
|
||||||
|
if (*a != *b) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *strcpy(char *dst, const char *src) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; src[i]; ++i) {
|
||||||
|
dst[i] = src[i];
|
||||||
|
}
|
||||||
|
dst[i] = 0;
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *strncpy(char *dst, const char *src, size_t lim) {
|
||||||
|
size_t i = 0;
|
||||||
|
while (i < lim) {
|
||||||
|
if (!src[i]) {
|
||||||
|
dst[i] = 0;
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
dst[i] = src[i];
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *strchr(const char *s, int c) {
|
||||||
|
while (*s) {
|
||||||
|
if (*s == (char) c) {
|
||||||
|
return (char *) s;
|
||||||
|
}
|
||||||
|
++s;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *strrchr(const char *s, int c) {
|
||||||
|
ssize_t l = (ssize_t) strlen(s);
|
||||||
|
if (!l) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
while (l >= 0) {
|
||||||
|
if (s[l] == (char) c) {
|
||||||
|
return (char *) &s[l];
|
||||||
|
}
|
||||||
|
--l;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int memcmp(const void *a, const void *b, size_t n) {
|
||||||
|
const char *l = a;
|
||||||
|
const char *r = b;
|
||||||
|
for (; n && *l == *r; --n, ++l, ++r);
|
||||||
|
return n ? *l - *r : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *memmove(void *dest, const void *src, size_t n) {
|
||||||
|
char *d = dest;
|
||||||
|
const char *s = src;
|
||||||
|
|
||||||
|
if (d == s) {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((s + n) <= d || (d + n) <= s) {
|
||||||
|
return memcpy(d, s, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d < s) {
|
||||||
|
if (((uintptr_t) s) % sizeof(size_t) == ((uintptr_t) d) % sizeof(size_t)) {
|
||||||
|
while (((uintptr_t) d) % sizeof(size_t)) {
|
||||||
|
if (!n--) {
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
*d++ = *s++;
|
||||||
|
}
|
||||||
|
for (; n >= sizeof(size_t); n -= sizeof(size_t), d += sizeof(size_t), s += sizeof(size_t)) {
|
||||||
|
*((size_t *) d) = *((size_t *) s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (; n; n--) {
|
||||||
|
*d++ = *s++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (((uintptr_t) s) % sizeof(size_t) == ((uintptr_t) d) % sizeof(size_t)) {
|
||||||
|
while (((uintptr_t) (d + n)) % sizeof(size_t)) {
|
||||||
|
if (!n--) {
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
d[n] = s[n];
|
||||||
|
}
|
||||||
|
while (n >= sizeof(size_t)) {
|
||||||
|
n -= sizeof(size_t);
|
||||||
|
*((size_t *) (d + n)) = *((size_t *) (s + n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (n) {
|
||||||
|
n--;
|
||||||
|
d[n] = s[n];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *memset(void *blk, int v, size_t sz) {
|
||||||
|
for (size_t i = 0; i < sz; ++i) {
|
||||||
|
((char *) blk)[i] = v;
|
||||||
|
}
|
||||||
|
return blk;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *memcpy(void *dst, const void *src, size_t sz) {
|
||||||
|
for (size_t i = 0; i < sz; ++i) {
|
||||||
|
((char *) dst)[i] = ((const char *) src)[i];
|
||||||
|
}
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
179
libc/syscall.c
Normal file
179
libc/syscall.c
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
#include "bits/syscall.h"
|
||||||
|
#include "bits/global.h"
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#define ASM_REGISTER(name) \
|
||||||
|
register uint64_t name asm (#name)
|
||||||
|
|
||||||
|
#define ASM_SYSCALL0(r0) ({ \
|
||||||
|
ASM_REGISTER(rax) = (uint64_t) (r0); \
|
||||||
|
asm volatile ("syscall":::"memory"); \
|
||||||
|
rax; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define ASM_SYSCALL1(r0, r1) ({ \
|
||||||
|
ASM_REGISTER(rdi) = (uint64_t) (r1); \
|
||||||
|
/*
|
||||||
|
* Should be the last one because memory accesses for arguments
|
||||||
|
* fuck up %rax
|
||||||
|
*/ \
|
||||||
|
ASM_REGISTER(rax) = (uint64_t) (r0); \
|
||||||
|
asm volatile ("syscall":::"memory"); \
|
||||||
|
rax; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define ASM_SYSCALL2(r0, r1, r2) ({ \
|
||||||
|
ASM_REGISTER(rdi) = (uint64_t) (r1); \
|
||||||
|
ASM_REGISTER(rsi) = (uint64_t) (r2); \
|
||||||
|
/*
|
||||||
|
* Should be the last one because memory accesses for arguments
|
||||||
|
* fuck up %rax
|
||||||
|
*/ \
|
||||||
|
ASM_REGISTER(rax) = (uint64_t) (r0); \
|
||||||
|
asm volatile ("syscall":::"memory", "rax", "rdi", "rsi", "rdx"); \
|
||||||
|
rax; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define ASM_SYSCALL3(r0, r1, r2, r3) ({ \
|
||||||
|
ASM_REGISTER(rdi) = (uint64_t) (r1); \
|
||||||
|
ASM_REGISTER(rsi) = (uint64_t) (r2); \
|
||||||
|
ASM_REGISTER(rdx) = (uint64_t) (r3); \
|
||||||
|
/*
|
||||||
|
* Should be the last one because memory accesses for arguments
|
||||||
|
* fuck up %rax
|
||||||
|
*/ \
|
||||||
|
ASM_REGISTER(rax) = (uint64_t) (r0); \
|
||||||
|
asm volatile ("syscall":::"memory", "rax", "rdi", "rsi", "rdx"); \
|
||||||
|
rax; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define ASM_SYSCALL4(r0, r1, r2, r3, r4) ({ \
|
||||||
|
ASM_REGISTER(rdi) = (uint64_t) (r1); \
|
||||||
|
ASM_REGISTER(rsi) = (uint64_t) (r2); \
|
||||||
|
ASM_REGISTER(rdx) = (uint64_t) (r3); \
|
||||||
|
ASM_REGISTER(r10) = (uint64_t) (r4); \
|
||||||
|
/*
|
||||||
|
* Should be the last one because memory accesses for arguments
|
||||||
|
* fuck up %rax
|
||||||
|
*/ \
|
||||||
|
ASM_REGISTER(rax) = (uint64_t) (r0); \
|
||||||
|
asm volatile ("syscall":::"memory", "rax", "rdi", "rsi", "rdx", "r10"); \
|
||||||
|
rax; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define SET_ERRNO(t, r) ({ \
|
||||||
|
t res = (t) r; \
|
||||||
|
if (res < 0) { \
|
||||||
|
errno = -res; \
|
||||||
|
} \
|
||||||
|
((int) res) < 0 ? (t) -1 : res; \
|
||||||
|
})
|
||||||
|
|
||||||
|
ssize_t write(int fd, const void *buf, size_t count) {
|
||||||
|
return SET_ERRNO(ssize_t, ASM_SYSCALL3(SYSCALL_NR_WRITE, fd, buf, count));
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t read(int fd, void *buf, size_t count) {
|
||||||
|
return SET_ERRNO(ssize_t, ASM_SYSCALL3(SYSCALL_NR_READ, fd, buf, count));
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t sys_readdir(int fd, struct dirent *entp) {
|
||||||
|
return SET_ERRNO(ssize_t, ASM_SYSCALL2(SYSCALL_NR_READDIR, fd, entp));
|
||||||
|
}
|
||||||
|
|
||||||
|
int open(const char *filename, int flags, int mode) {
|
||||||
|
return SET_ERRNO(int, ASM_SYSCALL3(SYSCALL_NR_OPEN, filename, flags, mode));
|
||||||
|
}
|
||||||
|
|
||||||
|
void close(int fd) {
|
||||||
|
(void) ASM_SYSCALL1(SYSCALL_NR_CLOSE, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int stat(const char *filename, struct stat *st) {
|
||||||
|
return SET_ERRNO(int, ASM_SYSCALL2(SYSCALL_NR_STAT, filename, st));
|
||||||
|
}
|
||||||
|
|
||||||
|
int brk(void *addr) {
|
||||||
|
return SET_ERRNO(int, ASM_SYSCALL1(SYSCALL_NR_BRK, addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
int fork(void) {
|
||||||
|
return SET_ERRNO(int, ASM_SYSCALL0(SYSCALL_NR_FORK));
|
||||||
|
}
|
||||||
|
|
||||||
|
int execve(const char *filename, const char *const argv[], const char *const envp[]) {
|
||||||
|
return SET_ERRNO(int, ASM_SYSCALL3(SYSCALL_NR_EXECVE, filename, argv, envp));
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((noreturn)) void exit(int code) {
|
||||||
|
(void) ASM_SYSCALL1(SYSCALL_NR_EXIT, code);
|
||||||
|
while (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int kill(int pid, int signum) {
|
||||||
|
return SET_ERRNO(int, ASM_SYSCALL2(SYSCALL_NR_KILL, pid, signum));
|
||||||
|
}
|
||||||
|
|
||||||
|
void __kernel_signal(uintptr_t entry) {
|
||||||
|
(void) ASM_SYSCALL1(SYSCALL_NRX_SIGNAL, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((noreturn)) void __kernel_sigret(void) {
|
||||||
|
(void) ASM_SYSCALL0(SYSCALL_NRX_SIGRET);
|
||||||
|
while (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int getpid(void) {
|
||||||
|
return ASM_SYSCALL0(SYSCALL_NR_GETPID);
|
||||||
|
}
|
||||||
|
|
||||||
|
int chdir(const char *filename) {
|
||||||
|
return SET_ERRNO(int, ASM_SYSCALL1(SYSCALL_NR_CHDIR, filename));
|
||||||
|
}
|
||||||
|
|
||||||
|
char *getcwd(char *buf, size_t lim) {
|
||||||
|
if (SET_ERRNO(int, ASM_SYSCALL2(SYSCALL_NR_GETCWD, buf, lim)) == 0) {
|
||||||
|
return buf;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int nanosleep(const struct timespec *req, struct timespec *rem) {
|
||||||
|
return SET_ERRNO(int, ASM_SYSCALL2(SYSCALL_NR_NANOSLEEP, req, rem));
|
||||||
|
}
|
||||||
|
|
||||||
|
int openpty(int *master, int *slave) {
|
||||||
|
return SET_ERRNO(int, ASM_SYSCALL2(SYSCALL_NRX_OPENPTY, master, slave));
|
||||||
|
}
|
||||||
|
|
||||||
|
int gettimeofday(struct timeval *tv, struct timezone *tz) {
|
||||||
|
return SET_ERRNO(int, ASM_SYSCALL2(SYSCALL_NR_GETTIMEOFDAY, tv, tz));
|
||||||
|
}
|
||||||
|
|
||||||
|
int reboot(int magic1, int magic2, unsigned int cmd, void *arg) {
|
||||||
|
return SET_ERRNO(int, ASM_SYSCALL4(SYSCALL_NR_REBOOT, magic1, magic2, cmd, arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
int access(const char *filename, int mode) {
|
||||||
|
return SET_ERRNO(int, ASM_SYSCALL2(SYSCALL_NR_ACCESS, filename, mode));
|
||||||
|
}
|
||||||
|
|
||||||
|
int waitpid(int pid, int *status) {
|
||||||
|
return SET_ERRNO(int, ASM_SYSCALL2(SYSCALL_NRX_WAITPID, pid, status));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Although sbrk() is implemented in userspace, I guess it should also be here
|
||||||
|
void *sbrk(intptr_t inc) {
|
||||||
|
if (inc == 0) {
|
||||||
|
return __cur_brk;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *new_brk = (void *) ((uintptr_t) __cur_brk + inc);
|
||||||
|
|
||||||
|
if (brk(new_brk) != 0) {
|
||||||
|
return __cur_brk;
|
||||||
|
} else {
|
||||||
|
return __cur_brk = new_brk;
|
||||||
|
}
|
||||||
|
}
|
7
libc/time.c
Normal file
7
libc/time.c
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#include "time.h"
|
||||||
|
#include "bits/syscall.h"
|
||||||
|
|
||||||
|
int usleep(long us) {
|
||||||
|
struct timespec tv = { us / 1000000, (us % 1000) * 1000 };
|
||||||
|
return nanosleep(&tv, NULL);
|
||||||
|
}
|
255
libc/vsnprintf.c
Normal file
255
libc/vsnprintf.c
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
#include "bits/printf.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
union printfv {
|
||||||
|
int value_int;
|
||||||
|
unsigned int value_uint;
|
||||||
|
long value_long;
|
||||||
|
uint32_t value_uint32;
|
||||||
|
uint64_t value_uint64;
|
||||||
|
uintptr_t value_ptr;
|
||||||
|
const char *value_str;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *s_print_xs_set0 = "0123456789abcdef";
|
||||||
|
static const char *s_print_xs_set1 = "0123456789ABCDEF";
|
||||||
|
|
||||||
|
static int vsnprintf_ds(int64_t x, char *res, int s, int sz) {
|
||||||
|
if (!x) {
|
||||||
|
res[0] = '0';
|
||||||
|
res[1] = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int c;
|
||||||
|
uint64_t v;
|
||||||
|
|
||||||
|
if (sz) {
|
||||||
|
if (s && x < 0) {
|
||||||
|
v = (uint64_t) -x;
|
||||||
|
} else {
|
||||||
|
s = 0;
|
||||||
|
v = (uint64_t) x;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (s && ((int32_t) x) < 0) {
|
||||||
|
v = (uint64_t) -((int32_t) x);
|
||||||
|
} else {
|
||||||
|
s = 0;
|
||||||
|
v = (uint64_t) x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c = 0;
|
||||||
|
|
||||||
|
while (v) {
|
||||||
|
res[c++] = '0' + v % 10;
|
||||||
|
v /= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s) {
|
||||||
|
res[c++] = '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
res[c] = 0;
|
||||||
|
|
||||||
|
for (int i = 0, j = c - 1; i < j; ++i, --j) {
|
||||||
|
res[i] ^= res[j];
|
||||||
|
res[j] ^= res[i];
|
||||||
|
res[i] ^= res[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vsnprintf_xs(uint64_t v, char *res, const char *set) {
|
||||||
|
if (!v) {
|
||||||
|
res[0] = '0';
|
||||||
|
res[1] = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int c = 0;
|
||||||
|
|
||||||
|
while (v) {
|
||||||
|
res[c++] = set[v & 0xF];
|
||||||
|
v >>= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
res[c] = 0;
|
||||||
|
|
||||||
|
for (int i = 0, j = c - 1; i < j; ++i, --j) {
|
||||||
|
res[i] ^= res[j];
|
||||||
|
res[j] ^= res[i];
|
||||||
|
res[i] ^= res[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int vsnprintf(char *buf, size_t len, const char *fmt, va_list args) {
|
||||||
|
union printfv val;
|
||||||
|
char cbuf[64];
|
||||||
|
size_t p = 0;
|
||||||
|
// padn > 0:
|
||||||
|
// --------vvvvv
|
||||||
|
// padn < 0:
|
||||||
|
// vvvv----------
|
||||||
|
int padn;
|
||||||
|
char padc;
|
||||||
|
int pads;
|
||||||
|
int clen;
|
||||||
|
char c;
|
||||||
|
|
||||||
|
#define __putc(ch) \
|
||||||
|
if (p == len - 1) { \
|
||||||
|
goto __end; \
|
||||||
|
} else { \
|
||||||
|
buf[p++] = ch; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define __puts(s, l) \
|
||||||
|
if (padn >= 0) { \
|
||||||
|
if (l < padn) { \
|
||||||
|
size_t padd = padn - l; \
|
||||||
|
if (p + padd < len + 1) { \
|
||||||
|
memset(buf + p, padc, padd); \
|
||||||
|
p += padd; \
|
||||||
|
} else { \
|
||||||
|
memset(buf + p, padc, len - 1 - p); \
|
||||||
|
p = len - 1; \
|
||||||
|
goto __end; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
if (p + l < len + 1) { \
|
||||||
|
strncpy(buf + p, s, l); \
|
||||||
|
p += l; \
|
||||||
|
} else { \
|
||||||
|
strncpy(buf + p, s, len - 1 - p); \
|
||||||
|
p = len - 1; \
|
||||||
|
goto __end; \
|
||||||
|
} \
|
||||||
|
} else { \
|
||||||
|
padn = -padn; \
|
||||||
|
if (p + l < len + 1) { \
|
||||||
|
strncpy(buf + p, s, l); \
|
||||||
|
p += l; \
|
||||||
|
} else { \
|
||||||
|
strncpy(buf + p, s, len - 1 - p); \
|
||||||
|
p = len - 1; \
|
||||||
|
goto __end; \
|
||||||
|
} \
|
||||||
|
if (l < padn) { \
|
||||||
|
size_t padd = padn - l; \
|
||||||
|
if (p + padd < len + 1) { \
|
||||||
|
memset(buf + p, padc, padd); \
|
||||||
|
p += padd; \
|
||||||
|
} else { \
|
||||||
|
memset(buf + p, padc, len - 1 - p); \
|
||||||
|
p = len - 1; \
|
||||||
|
goto __end; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((c = *fmt)) {
|
||||||
|
switch (c) {
|
||||||
|
case '%':
|
||||||
|
c = *++fmt;
|
||||||
|
padn = 0;
|
||||||
|
padc = ' ';
|
||||||
|
pads = 1;
|
||||||
|
|
||||||
|
if (c == '0') {
|
||||||
|
padc = c;
|
||||||
|
c = *++fmt;
|
||||||
|
}
|
||||||
|
if (c == '-') {
|
||||||
|
pads = -1;
|
||||||
|
c = *++fmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (c >= '0' && c <= '9') {
|
||||||
|
padn *= 10;
|
||||||
|
padn += c - '0';
|
||||||
|
c = *++fmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
padn *= pads;
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case 'l':
|
||||||
|
// Not supported
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
if ((val.value_str = va_arg(args, const char *))) {
|
||||||
|
__puts(val.value_str, strlen(val.value_str));
|
||||||
|
} else {
|
||||||
|
__puts("(null)", 6);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'p':
|
||||||
|
val.value_ptr = va_arg(args, uintptr_t);
|
||||||
|
__putc('0');
|
||||||
|
__putc('x');
|
||||||
|
padn = sizeof(uintptr_t) * 2;
|
||||||
|
padc = '0';
|
||||||
|
clen = vsnprintf_xs(val.value_ptr, cbuf, s_print_xs_set0);
|
||||||
|
__puts(cbuf, clen);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'i':
|
||||||
|
case 'd':
|
||||||
|
val.value_int = va_arg(args, int);
|
||||||
|
clen = vsnprintf_ds(val.value_int, cbuf, 1, 1);
|
||||||
|
__puts(cbuf, clen);
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
val.value_uint = va_arg(args, unsigned int);
|
||||||
|
clen = vsnprintf_ds(val.value_uint, cbuf, 0, 1);
|
||||||
|
__puts(cbuf, clen);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'x':
|
||||||
|
val.value_uint32 = va_arg(args, uint32_t);
|
||||||
|
clen = vsnprintf_xs(val.value_uint32, cbuf, s_print_xs_set0);
|
||||||
|
__puts(cbuf, clen);
|
||||||
|
break;
|
||||||
|
case 'X':
|
||||||
|
val.value_uint32 = va_arg(args, uint32_t);
|
||||||
|
clen = vsnprintf_xs(val.value_uint32, cbuf, s_print_xs_set1);
|
||||||
|
__puts(cbuf, clen);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'c':
|
||||||
|
val.value_int = va_arg(args, int);
|
||||||
|
__putc(val.value_int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
__putc('%');
|
||||||
|
__putc(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
__putc(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
++fmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef __puts
|
||||||
|
#undef __putc
|
||||||
|
|
||||||
|
__end:
|
||||||
|
buf[p] = 0;
|
||||||
|
return p;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user