mirror of
https://github.com/Fennix-Project/Userspace.git
synced 2025-05-25 22:14:28 +00:00
Update userspace
This commit is contained in:
parent
17787dbc9b
commit
c685a37c15
6
.vscode/launch.json
vendored
6
.vscode/launch.json
vendored
@ -35,7 +35,7 @@
|
|||||||
"description": "Load binary."
|
"description": "Load binary."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"text": "add-symbol-file ${workspaceFolder}/../Kernel/kernel.fsys",
|
"text": "add-symbol-file ${workspaceFolder}/../Kernel/fennix.elf",
|
||||||
"description": "Load kernel binary."
|
"description": "Load kernel binary."
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@ -74,7 +74,7 @@
|
|||||||
"description": "Load binary."
|
"description": "Load binary."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"text": "add-symbol-file ${workspaceFolder}/../Kernel/kernel.fsys",
|
"text": "add-symbol-file ${workspaceFolder}/../Kernel/fennix.elf",
|
||||||
"description": "Load kernel binary."
|
"description": "Load kernel binary."
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@ -113,7 +113,7 @@
|
|||||||
"description": "Load binary."
|
"description": "Load binary."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"text": "add-symbol-file ${workspaceFolder}/../Kernel/kernel.fsys",
|
"text": "add-symbol-file ${workspaceFolder}/../Kernel/fennix.elf",
|
||||||
"description": "Load kernel binary."
|
"description": "Load kernel binary."
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
6
Doxyfile
6
Doxyfile
@ -44,7 +44,7 @@ PROJECT_NUMBER = 1.0.0
|
|||||||
# for a project that appears at the top of each page and should give viewer a
|
# for a project that appears at the top of each page and should give viewer a
|
||||||
# quick idea about the purpose of the project. Keep the description short.
|
# quick idea about the purpose of the project. Keep the description short.
|
||||||
|
|
||||||
PROJECT_BRIEF = "Fennix Userspace Documentation"
|
PROJECT_BRIEF = "Userspace Documentation"
|
||||||
|
|
||||||
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
|
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
|
||||||
# in the documentation. The maximum height of the logo should not exceed 55
|
# in the documentation. The maximum height of the logo should not exceed 55
|
||||||
@ -864,7 +864,7 @@ WARN_LOGFILE =
|
|||||||
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
||||||
# Note: If this tag is empty the current directory is searched.
|
# Note: If this tag is empty the current directory is searched.
|
||||||
|
|
||||||
INPUT = Userspace tools/Doxygen_README.md
|
INPUT = Userspace tools/doxymds/userspace.md
|
||||||
|
|
||||||
# This tag can be used to specify the character encoding of the source files
|
# This tag can be used to specify the character encoding of the source files
|
||||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||||
@ -1064,7 +1064,7 @@ FILTER_SOURCE_PATTERNS =
|
|||||||
# (index.html). This can be useful if you have a project on for instance GitHub
|
# (index.html). This can be useful if you have a project on for instance GitHub
|
||||||
# and want to reuse the introduction page also for the doxygen output.
|
# and want to reuse the introduction page also for the doxygen output.
|
||||||
|
|
||||||
USE_MDFILE_AS_MAINPAGE = tools/Doxygen_README.md
|
USE_MDFILE_AS_MAINPAGE = tools/doxymds/userspace.md
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# Configuration options related to source browsing
|
# Configuration options related to source browsing
|
||||||
|
3
Makefile
3
Makefile
@ -31,12 +31,15 @@ MUSL_CONFIGURE_FLAGS += --enable-debug
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
build_musl:
|
build_musl:
|
||||||
|
ifeq ($(wildcard cache/musl),)
|
||||||
mkdir -p cache/musl
|
mkdir -p cache/musl
|
||||||
cd cache/musl && \
|
cd cache/musl && \
|
||||||
../../musl/configure --prefix=$(PREFIX) \
|
../../musl/configure --prefix=$(PREFIX) \
|
||||||
--target=$(TARGET) --includedir=$(PREFIX)/include \
|
--target=$(TARGET) --includedir=$(PREFIX)/include \
|
||||||
$(MUSL_CONFIGURE_FLAGS)
|
$(MUSL_CONFIGURE_FLAGS)
|
||||||
make -C cache/musl -j$(shell nproc)
|
make -C cache/musl -j$(shell nproc)
|
||||||
|
endif
|
||||||
|
$(info Installing musl libc)
|
||||||
cd cache/musl && make TARGET=$(TARGET) install
|
cd cache/musl && make TARGET=$(TARGET) install
|
||||||
cp out/lib/crt1.o out/lib/crt0.o
|
cp out/lib/crt1.o out/lib/crt0.o
|
||||||
cd out/lib && ln -s /lib/libc.so ./ld-musl-x86_64.so.1 && \
|
cd out/lib && ln -s /lib/libc.so ./ld-musl-x86_64.so.1 && \
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
# Config file
|
||||||
|
include ../../../Makefile.conf
|
||||||
|
|
||||||
cwd := $(CURDIR)
|
cwd := $(CURDIR)
|
||||||
CACHE_DIR := $(cwd)/../../cache
|
CACHE_DIR := $(cwd)/../../cache
|
||||||
PREFIX := $(cwd)/../../out/
|
PREFIX := $(cwd)/../../out/
|
||||||
@ -50,9 +53,13 @@ endif
|
|||||||
build:
|
build:
|
||||||
make -C echo build
|
make -C echo build
|
||||||
make -C fsh build
|
make -C fsh build
|
||||||
|
make -C utest build
|
||||||
|
make -C cross_test build
|
||||||
# $(MAKE) build_busybox
|
# $(MAKE) build_busybox
|
||||||
# $(MAKE) build_bash
|
# $(MAKE) build_bash
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
make -C echo clean
|
make -C echo clean
|
||||||
make -C fsh clean
|
make -C fsh clean
|
||||||
|
make -C utest clean
|
||||||
|
make -C cross_test clean
|
||||||
|
16
apps/base/cross_test/Makefile
Normal file
16
apps/base/cross_test/Makefile
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
WORKSPACE := ../../../
|
||||||
|
|
||||||
|
# Config file
|
||||||
|
include ../$(WORKSPACE)Makefile.conf
|
||||||
|
|
||||||
|
FILENAME = utest_
|
||||||
|
|
||||||
|
CFLAGS = -static -g -ggdb3 -O0
|
||||||
|
|
||||||
|
build:
|
||||||
|
$(info Compiling $(FILENAME)linux)
|
||||||
|
gcc linux_glibc.c $(CFLAGS) -o $(WORKSPACE)out/bin/$(FILENAME)linux
|
||||||
|
$(info Compiling $(FILENAME)win)
|
||||||
|
x86_64-w64-mingw32-gcc win_mingw.c $(CFLAGS) -o $(WORKSPACE)out/bin/$(FILENAME)win.exe
|
||||||
|
|
||||||
|
clean:
|
22
apps/base/cross_test/expected_glibc.txt
Normal file
22
apps/base/cross_test/expected_glibc.txt
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
$ setarch `uname -m` -R strace ./utest_linux
|
||||||
|
|
||||||
|
execve("./utest_linux", ["./utest_linux"], 0x7fffffffdec0 /* 56 vars */) = 0
|
||||||
|
arch_prctl(0x3001 /* ARCH_??? */, 0x7fffffffde40) = -1 EINVAL (Invalid argument)
|
||||||
|
brk(NULL) = 0x4cd000
|
||||||
|
brk(0x4cddc0) = 0x4cddc0
|
||||||
|
arch_prctl(ARCH_SET_FS, 0x4cd3c0) = 0
|
||||||
|
set_tid_address(0x4cd690) = 68565
|
||||||
|
set_robust_list(0x4cd6a0, 24) = 0
|
||||||
|
rseq(0x4cdd60, 0x20, 0, 0x53053053) = 0
|
||||||
|
uname({sysname="Fennix", nodename="fennix", ...}) = 0
|
||||||
|
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
|
||||||
|
readlink("/proc/self/exe", "/bin/utest_linux"..., 4096) = 50
|
||||||
|
getrandom("\x1e\x3c\x20\xdd\x09\xe8\x46\x0d", 8, GRND_NONBLOCK) = 8
|
||||||
|
brk(0x4eedc0) = 0x4eedc0
|
||||||
|
brk(0x4ef000) = 0x4ef000
|
||||||
|
mprotect(0x4c1000, 16384, PROT_READ) = 0
|
||||||
|
newfstatat(1, "", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x1), ...}, AT_EMPTY_PATH) = 0
|
||||||
|
write(1, "Hello, World!\n", 14Hello, World!
|
||||||
|
) = 14
|
||||||
|
exit_group(0) = ?
|
||||||
|
+++ exited with 0 +++
|
9
apps/base/cross_test/linux_glibc.c
Normal file
9
apps/base/cross_test/linux_glibc.c
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[], char *envp[])
|
||||||
|
{
|
||||||
|
printf("glibc: Hello, World!\n");
|
||||||
|
fflush(stdout);
|
||||||
|
return 0;
|
||||||
|
}
|
9
apps/base/cross_test/win_mingw.c
Normal file
9
apps/base/cross_test/win_mingw.c
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[], char *envp[])
|
||||||
|
{
|
||||||
|
printf("mingw: Hello, World!\n");
|
||||||
|
fflush(stdout);
|
||||||
|
return 0;
|
||||||
|
}
|
@ -1,15 +1,59 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
if (argc == 1)
|
int enableEscapes = 0;
|
||||||
|
int disableNewline = 0;
|
||||||
|
|
||||||
|
int opt;
|
||||||
|
while ((opt = getopt(argc, argv, "neE")) != -1)
|
||||||
{
|
{
|
||||||
printf("Usage: echo [args]\n");
|
switch (opt)
|
||||||
return 0;
|
{
|
||||||
|
case 'n':
|
||||||
|
disableNewline = 1;
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
enableEscapes = 1;
|
||||||
|
break;
|
||||||
|
case 'E':
|
||||||
|
enableEscapes = 0;
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
default:
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 1; i < argc; i++)
|
(void)enableEscapes;
|
||||||
printf("%s ", argv[i]);
|
|
||||||
printf("\n");
|
size_t totalLength = 0;
|
||||||
|
for (int i = optind; i < argc; ++i)
|
||||||
|
totalLength += strlen(argv[i]) + 1;
|
||||||
|
|
||||||
|
char *result = (char *)malloc(totalLength);
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
perror("Memory allocation error");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
result[0] = '\0';
|
||||||
|
|
||||||
|
for (int i = optind; i < argc; ++i)
|
||||||
|
{
|
||||||
|
strcat(result, argv[i]);
|
||||||
|
if (i < argc - 1)
|
||||||
|
strcat(result, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%s", result);
|
||||||
|
|
||||||
|
if (!disableNewline)
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
free(result);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,160 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
int main(int argc, char *argv[], char *envp[])
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <signal.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#define _POSIX_SOURCE
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define MAX_COMMAND_LENGTH 1024
|
||||||
|
#define MAX_ARGS 10
|
||||||
|
|
||||||
|
void DisableInputBuffering()
|
||||||
{
|
{
|
||||||
printf("Hello, world!\n");
|
struct termios tty_attr;
|
||||||
|
tcgetattr(STDIN_FILENO, &tty_attr);
|
||||||
|
tty_attr.c_lflag &= ~(ICANON | ECHO);
|
||||||
|
tcsetattr(STDIN_FILENO, TCSANOW, &tty_attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnableInputBuffering()
|
||||||
|
{
|
||||||
|
struct termios tty_attr;
|
||||||
|
tcgetattr(STDIN_FILENO, &tty_attr);
|
||||||
|
tty_attr.c_lflag |= ICANON | ECHO;
|
||||||
|
tcsetattr(STDIN_FILENO, TCSANOW, &tty_attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadLine(char *Buffer, size_t BufferSize)
|
||||||
|
{
|
||||||
|
size_t index = 0;
|
||||||
|
int c;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
c = getchar();
|
||||||
|
if (c == EOF || c == '\n')
|
||||||
|
{
|
||||||
|
Buffer[index] = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (c == 127 || c == 8) // Backspace
|
||||||
|
{
|
||||||
|
if (index > 0)
|
||||||
|
{
|
||||||
|
printf("\b \b");
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (c == 4) // Ctrl + D
|
||||||
|
{
|
||||||
|
if (index == 0)
|
||||||
|
kill(getpid(), SIGQUIT);
|
||||||
|
else
|
||||||
|
putchar('\a');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (index < BufferSize - 1)
|
||||||
|
{
|
||||||
|
putchar(c);
|
||||||
|
Buffer[index] = (char)c;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExecuteCommand(char *command)
|
||||||
|
{
|
||||||
|
char *args[MAX_ARGS];
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
char *token = strtok(command, " ");
|
||||||
|
while (token != NULL && i < MAX_ARGS - 1)
|
||||||
|
{
|
||||||
|
args[i++] = token;
|
||||||
|
token = strtok(NULL, " ");
|
||||||
|
}
|
||||||
|
args[i] = NULL;
|
||||||
|
|
||||||
|
pid_t pid = fork();
|
||||||
|
if (pid == 0)
|
||||||
|
{
|
||||||
|
execvp(args[0], args);
|
||||||
|
perror("execvp");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
else if (pid > 0)
|
||||||
|
wait(NULL);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
perror("fork");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleSignal(int signal)
|
||||||
|
{
|
||||||
|
if (signal == SIGQUIT)
|
||||||
|
{
|
||||||
|
EnableInputBuffering();
|
||||||
|
printf("\n");
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
else if (signal == SIGINT)
|
||||||
|
{
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
else if (signal == SIGHUP)
|
||||||
|
{
|
||||||
|
EnableInputBuffering();
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
else if (signal == SIGCHLD)
|
||||||
|
wait(NULL);
|
||||||
|
else if (signal == SIGSEGV)
|
||||||
|
{
|
||||||
|
printf("Segmentation fault\n");
|
||||||
|
while (1)
|
||||||
|
sleep(1000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Signal %s(%d) received\n",
|
||||||
|
strsignal(signal), signal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
char command[MAX_COMMAND_LENGTH];
|
||||||
|
for (int i = 0; i < NSIG; ++i)
|
||||||
|
signal(i, HandleSignal);
|
||||||
|
|
||||||
|
char hostname[256];
|
||||||
|
gethostname(hostname, sizeof(hostname));
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
printf("\033[1;32m");
|
||||||
|
printf("┌──(%s@%s)-[%s]\n", getenv("USER"), hostname, getenv("PWD"));
|
||||||
|
printf("└$ ");
|
||||||
|
printf("\033[0m");
|
||||||
|
|
||||||
|
DisableInputBuffering();
|
||||||
|
ReadLine(command, sizeof(command));
|
||||||
|
EnableInputBuffering();
|
||||||
|
putchar('\n');
|
||||||
|
|
||||||
|
if (strcmp(command, "exit") == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ExecuteCommand(command);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
66
apps/base/utest/Makefile
Normal file
66
apps/base/utest/Makefile
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
WORKSPACE := ../../../
|
||||||
|
|
||||||
|
# Config file
|
||||||
|
include ../$(WORKSPACE)Makefile.conf
|
||||||
|
|
||||||
|
CC = ../$(WORKSPACE)$(COMPILER_PATH)/$(COMPILER_ARCH)gcc
|
||||||
|
CPP = ../$(WORKSPACE)$(COMPILER_PATH)/$(COMPILER_ARCH)g++
|
||||||
|
LD = ../$(WORKSPACE)$(COMPILER_PATH)/$(COMPILER_ARCH)ld
|
||||||
|
AS = ../$(WORKSPACE)$(COMPILER_PATH)/$(COMPILER_ARCH)as
|
||||||
|
OBJDUMP = ../$(WORKSPACE)$(COMPILER_PATH)/$(COMPILER_ARCH)objdump
|
||||||
|
|
||||||
|
GIT_COMMIT = $(shell git rev-parse HEAD)
|
||||||
|
GIT_COMMIT_SHORT = $(shell git rev-parse --short HEAD)
|
||||||
|
|
||||||
|
ifeq ($(OSARCH), amd64)
|
||||||
|
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/i386/*" -not -path "./arch/aarch64/*")
|
||||||
|
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/i386/*" -not -path "./arch/aarch64/*")
|
||||||
|
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/i386/*" -not -path "./arch/aarch64/*")
|
||||||
|
else ifeq ($(OSARCH), i386)
|
||||||
|
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*")
|
||||||
|
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*")
|
||||||
|
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*")
|
||||||
|
else ifeq ($(OSARCH), aarch64)
|
||||||
|
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/amd64/*" -not -path "./arch/i386/*")
|
||||||
|
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/amd64/*" -not -path "./arch/i386/*")
|
||||||
|
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/amd64/*" -not -path "./arch/i386/*")
|
||||||
|
endif
|
||||||
|
OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(ASM_SOURCES:.asm=.o) $(S_SOURCES:.S=.o) $(PSF_SOURCES:.psf=.o) $(BMP_SOURCES:.bmp=.o)
|
||||||
|
|
||||||
|
SYSROOT = --sysroot=$(WORKSPACE)out/
|
||||||
|
FILENAME = utest
|
||||||
|
|
||||||
|
HEADERS = $(sort $(dir $(wildcard $(WORKSPACE)out/include/*)))
|
||||||
|
|
||||||
|
LDFLAGS =
|
||||||
|
CFLAGS = -I$(WORKSPACE)out/include \
|
||||||
|
-DGIT_COMMIT='"$(GIT_COMMIT)"' \
|
||||||
|
-DGIT_COMMIT_SHORT='"$(GIT_COMMIT_SHORT)"'
|
||||||
|
WARNCFLAG = -Wall -Wextra
|
||||||
|
|
||||||
|
ifeq ($(DEBUG), 1)
|
||||||
|
CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fverbose-asm
|
||||||
|
LDFLAGS += -ggdb3 -O0
|
||||||
|
endif
|
||||||
|
|
||||||
|
build: $(FILENAME)
|
||||||
|
mv $(FILENAME) $(WORKSPACE)out/bin/$(FILENAME)
|
||||||
|
|
||||||
|
$(FILENAME): $(OBJ)
|
||||||
|
$(info Linking $@)
|
||||||
|
$(CC) $(LDFLAGS) $(SYSROOT) $(OBJ) -o $@
|
||||||
|
|
||||||
|
%.o: %.c $(HEADERS)
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@
|
||||||
|
|
||||||
|
%.o: %.cpp $(HEADERS)
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fexceptions -c $< -o $@ -fno-rtti
|
||||||
|
|
||||||
|
%.o: %.S
|
||||||
|
$(info Compiling $<)
|
||||||
|
$(AS) -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJ)
|
810
apps/base/utest/userspace_test.c
Normal file
810
apps/base/utest/userspace_test.c
Normal file
@ -0,0 +1,810 @@
|
|||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#define _POSIX_SOURCE
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/inotify.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <pty.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/reboot.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
|
||||||
|
#define AT_NULL 0
|
||||||
|
#define AT_IGNORE 1
|
||||||
|
#define AT_EXECFD 2
|
||||||
|
#define AT_PHDR 3
|
||||||
|
#define AT_PHENT 4
|
||||||
|
#define AT_PHNUM 5
|
||||||
|
#define AT_PAGESZ 6
|
||||||
|
#define AT_BASE 7
|
||||||
|
#define AT_FLAGS 8
|
||||||
|
#define AT_ENTRY 9
|
||||||
|
#define AT_NOTELF 10
|
||||||
|
#define AT_UID 11
|
||||||
|
#define AT_EUID 12
|
||||||
|
#define AT_GID 13
|
||||||
|
#define AT_EGID 14
|
||||||
|
#define AT_PLATFORM 15
|
||||||
|
#define AT_HWCAP 16
|
||||||
|
#define AT_CLKTCK 17
|
||||||
|
#define AT_SECURE 23
|
||||||
|
#define AT_BASE_PLATFORM 24
|
||||||
|
#define AT_RANDOM 25
|
||||||
|
#define AT_HWCAP2 26
|
||||||
|
#define AT_EXECFN 31
|
||||||
|
#define AT_SYSINFO 32
|
||||||
|
#define AT_SYSINFO_EHDR 33
|
||||||
|
#define AT_L1I_CACHESHAPE 34
|
||||||
|
#define AT_L1D_CACHESHAPE 35
|
||||||
|
#define AT_L2_CACHESHAPE 36
|
||||||
|
#define AT_L3_CACHESHAPE 37
|
||||||
|
#define AT_L1I_CACHESIZE 40
|
||||||
|
#define AT_L1I_CACHEGEOMETRY 41
|
||||||
|
#define AT_L1D_CACHESIZE 42
|
||||||
|
#define AT_L1D_CACHEGEOMETRY 43
|
||||||
|
#define AT_L2_CACHESIZE 44
|
||||||
|
#define AT_L2_CACHEGEOMETRY 45
|
||||||
|
#define AT_L3_CACHESIZE 46
|
||||||
|
#define AT_L3_CACHEGEOMETRY 47
|
||||||
|
#define AT_MINSIGSTKSZ 51
|
||||||
|
|
||||||
|
#define EVENT_SIZE (sizeof(struct inotify_event))
|
||||||
|
#define BUF_LEN (1024 * (EVENT_SIZE + 16))
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t a_type;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint32_t a_val;
|
||||||
|
} a_un;
|
||||||
|
} Elf32_auxv_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint64_t a_type;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint64_t a_val;
|
||||||
|
} a_un;
|
||||||
|
} Elf64_auxv_t;
|
||||||
|
|
||||||
|
#ifdef __LP64__
|
||||||
|
#define Elf_auxv_t Elf64_auxv_t
|
||||||
|
#else
|
||||||
|
#define Elf_auxv_t Elf32_auxv_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define loop \
|
||||||
|
while (1) \
|
||||||
|
;
|
||||||
|
|
||||||
|
#define __musl_SYS_brk 12
|
||||||
|
|
||||||
|
static __inline long __musl_syscall1(long n, long a1)
|
||||||
|
{
|
||||||
|
unsigned long ret;
|
||||||
|
__asm__ __volatile__("syscall"
|
||||||
|
: "=a"(ret)
|
||||||
|
: "a"(n), "D"(a1)
|
||||||
|
: "rcx", "r11", "memory");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
long __musl_syscall_ret(unsigned long r)
|
||||||
|
{
|
||||||
|
if (r > -4096UL)
|
||||||
|
{
|
||||||
|
errno = -r;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct passwd *p = NULL;
|
||||||
|
|
||||||
|
void test_passwd()
|
||||||
|
{
|
||||||
|
printf("- Testing passwd\n");
|
||||||
|
|
||||||
|
p = getpwuid(getuid());
|
||||||
|
if (p == NULL)
|
||||||
|
{
|
||||||
|
perror("getpwuid");
|
||||||
|
fflush(stdout);
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("name: %s\n", p->pw_name);
|
||||||
|
printf("passwd: %s\n", p->pw_passwd);
|
||||||
|
printf("uid: %d\n", p->pw_uid);
|
||||||
|
printf("gid: %d\n", p->pw_gid);
|
||||||
|
printf("gecos: %s\n", p->pw_gecos);
|
||||||
|
printf("dir: %s\n", p->pw_dir);
|
||||||
|
printf("shell: %s\n", p->pw_shell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *heap_end = NULL;
|
||||||
|
void *__libc_sbrk(intptr_t increment)
|
||||||
|
{
|
||||||
|
if (heap_end == NULL)
|
||||||
|
{
|
||||||
|
heap_end = (void *)__musl_syscall1(__musl_SYS_brk, 0);
|
||||||
|
printf("SYS_brk(0) = %p\n", heap_end);
|
||||||
|
|
||||||
|
heap_end = (void *)__musl_syscall1(__musl_SYS_brk, (long)heap_end + 0x2000);
|
||||||
|
printf("Adding 0x2000 to heap_end: %p\n", heap_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (increment == 0)
|
||||||
|
{
|
||||||
|
printf("Returning heap_end: %p\n", heap_end);
|
||||||
|
return heap_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *old_heap_end = heap_end;
|
||||||
|
|
||||||
|
long ret = __musl_syscall1(__musl_SYS_brk, (long)heap_end + increment);
|
||||||
|
printf("SYS_brk(%p) = %p\n", (void *)((long)heap_end + increment), (void *)ret);
|
||||||
|
if (ret == 0)
|
||||||
|
{
|
||||||
|
heap_end = (void *)__musl_syscall1(__musl_SYS_brk, 0);
|
||||||
|
printf("SYS_brk(0) = %p\n", heap_end);
|
||||||
|
return old_heap_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (void *)__musl_syscall_ret(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_brk()
|
||||||
|
{
|
||||||
|
printf("- Testing brk\n");
|
||||||
|
|
||||||
|
void *current_brk = __libc_sbrk(0);
|
||||||
|
printf("Initial break address: %p\n", current_brk);
|
||||||
|
|
||||||
|
void *new_brk = __libc_sbrk(0x1000);
|
||||||
|
if (new_brk == (void *)-1)
|
||||||
|
{
|
||||||
|
perror("Error extending heap");
|
||||||
|
fflush(stdout);
|
||||||
|
fflush(stderr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf("Heap extended successfully.\n");
|
||||||
|
|
||||||
|
printf("New break address: %p\n", new_brk);
|
||||||
|
|
||||||
|
if (__libc_sbrk(current_brk - new_brk) == (void *)-1)
|
||||||
|
{
|
||||||
|
perror("Error reducing heap");
|
||||||
|
fflush(stdout);
|
||||||
|
fflush(stderr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Heap reduced successfully.\n");
|
||||||
|
printf("Current break address after reduction: %p\n", __libc_sbrk(0));
|
||||||
|
|
||||||
|
void *extended_brk = __libc_sbrk(0x1000);
|
||||||
|
if (extended_brk == (void *)-1)
|
||||||
|
{
|
||||||
|
perror("Error extending heap after reduction");
|
||||||
|
fflush(stdout);
|
||||||
|
fflush(stderr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Heap extended successfully after reduction.\n");
|
||||||
|
printf("New break address after extension: %p\n", extended_brk);
|
||||||
|
|
||||||
|
__libc_sbrk(-0x1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_time()
|
||||||
|
{
|
||||||
|
printf("- Testing time\n");
|
||||||
|
|
||||||
|
struct tm time = {0};
|
||||||
|
int Year = 2024;
|
||||||
|
int Month = 1;
|
||||||
|
int Day = 1;
|
||||||
|
int Hour = 0;
|
||||||
|
int Minute = 0;
|
||||||
|
int Second = 0;
|
||||||
|
|
||||||
|
time.tm_year = Year - 1900;
|
||||||
|
time.tm_mon = Month - 1;
|
||||||
|
time.tm_mday = Day;
|
||||||
|
time.tm_hour = Hour;
|
||||||
|
time.tm_min = Minute;
|
||||||
|
time.tm_sec = Second;
|
||||||
|
|
||||||
|
if (time.tm_year < 0)
|
||||||
|
time.tm_year = 0;
|
||||||
|
|
||||||
|
time_t t = mktime(&time);
|
||||||
|
if (t != (time_t)-1)
|
||||||
|
stime(&t);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
perror("mktime");
|
||||||
|
fflush(stdout);
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_args(int argc, char *argv[], char *envp[])
|
||||||
|
{
|
||||||
|
printf("- Testing args\n");
|
||||||
|
|
||||||
|
printf("%p %p %p\n",
|
||||||
|
(void *)(uintptr_t)&argc,
|
||||||
|
(void *)&argv,
|
||||||
|
(void *)&envp);
|
||||||
|
|
||||||
|
printf("I have %d arguments\n", argc);
|
||||||
|
for (int i = 0; i < argc; i++)
|
||||||
|
printf("argv[%d] = (%p) %s\n", i, argv[i], argv[i]);
|
||||||
|
|
||||||
|
int envc = 0;
|
||||||
|
while (envp[envc] != NULL)
|
||||||
|
envc++;
|
||||||
|
|
||||||
|
printf("I have %d environment variables\n", envc);
|
||||||
|
for (int i = 0; i < envc; i++)
|
||||||
|
printf("envp[%d] = (%p) %s\n", i, envp[i], envp[i]);
|
||||||
|
|
||||||
|
Elf64_auxv_t *auxv;
|
||||||
|
char **e = envp;
|
||||||
|
|
||||||
|
while (*e++ != NULL)
|
||||||
|
;
|
||||||
|
|
||||||
|
for (auxv = (Elf64_auxv_t *)e; auxv->a_type != AT_NULL; auxv++)
|
||||||
|
printf("auxv: %ld %#lx\n", auxv->a_type, auxv->a_un.a_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_stdio()
|
||||||
|
{
|
||||||
|
printf("- Testing stdin\n");
|
||||||
|
|
||||||
|
pid_t pid = fork();
|
||||||
|
if (pid < 0)
|
||||||
|
{
|
||||||
|
perror("fork");
|
||||||
|
fflush(stdout);
|
||||||
|
fflush(stderr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (pid != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
printf("Type a character: ");
|
||||||
|
char c = getchar();
|
||||||
|
printf("You typed: %c (%#x)\n", c, c);
|
||||||
|
char *line = NULL;
|
||||||
|
size_t len = 0;
|
||||||
|
ssize_t read;
|
||||||
|
printf("Type a line: ");
|
||||||
|
read = getline(&line, &len, stdin);
|
||||||
|
printf("You typed: %s (%ld bytes)\n", line, read);
|
||||||
|
free(line);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_file()
|
||||||
|
{
|
||||||
|
printf("- Testing file operations\n");
|
||||||
|
|
||||||
|
FILE *test = fopen("/etc/passwd", "r");
|
||||||
|
if (test == NULL)
|
||||||
|
{
|
||||||
|
perror("fopen");
|
||||||
|
fflush(stdout);
|
||||||
|
fflush(stderr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("/etc/passwd contents: ");
|
||||||
|
char ch;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
ch = fgetc(test);
|
||||||
|
if (ch == EOF)
|
||||||
|
{
|
||||||
|
printf("\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
putchar(ch);
|
||||||
|
}
|
||||||
|
fclose(test);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_ptmx()
|
||||||
|
{
|
||||||
|
printf("- Testing PTMX\n");
|
||||||
|
|
||||||
|
int master, slave;
|
||||||
|
char buffer[256];
|
||||||
|
|
||||||
|
if (openpty(&master, &slave, NULL, NULL, NULL) == -1)
|
||||||
|
{
|
||||||
|
perror("openpty");
|
||||||
|
fflush(stdout);
|
||||||
|
fflush(stderr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
write(master, "Hello, pty!\n", 12);
|
||||||
|
ssize_t bytesRead = read(slave, buffer, sizeof(buffer));
|
||||||
|
if (bytesRead > 0)
|
||||||
|
{
|
||||||
|
buffer[bytesRead] = '\0';
|
||||||
|
printf("Received from pty: %s", buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
close(master);
|
||||||
|
close(slave);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_system()
|
||||||
|
{
|
||||||
|
printf("- Testing system()\n");
|
||||||
|
int ret = system("echo Hello, world!");
|
||||||
|
printf("system() returned %d\n", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sigRec = 0;
|
||||||
|
void signalHandler(int signo)
|
||||||
|
{
|
||||||
|
if (signo == SIGUSR1)
|
||||||
|
printf("Signal received\n");
|
||||||
|
else
|
||||||
|
printf("Unknown signal received %d\n", signo);
|
||||||
|
sigRec = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_signal()
|
||||||
|
{
|
||||||
|
printf("- Testing Signals\n");
|
||||||
|
signal(SIGUSR1, signalHandler);
|
||||||
|
signal(SIGUSR2, signalHandler);
|
||||||
|
printf("Sending SIGUSR1...\n");
|
||||||
|
kill(getpid(), SIGUSR1);
|
||||||
|
printf("Sending SIGUSR2...\n");
|
||||||
|
kill(getpid(), SIGUSR2);
|
||||||
|
printf("Signal sent\n");
|
||||||
|
while (!sigRec)
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_execve_fork()
|
||||||
|
{
|
||||||
|
printf("- Testing execve and fork\n");
|
||||||
|
|
||||||
|
pid_t pid = fork();
|
||||||
|
if (pid == 0) // Child process
|
||||||
|
{
|
||||||
|
pid_t pid2 = fork();
|
||||||
|
if (pid2 == 0) // Child process
|
||||||
|
{
|
||||||
|
char *shebangArgs[] = {"/test.sh", NULL};
|
||||||
|
execv(shebangArgs[0], shebangArgs);
|
||||||
|
perror("execv");
|
||||||
|
fflush(stdout);
|
||||||
|
fflush(stderr);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Creating shell process\n");
|
||||||
|
char *args[] = {"/bin/echo", "Hello World from echo!", NULL};
|
||||||
|
execv(args[0], args);
|
||||||
|
perror("execv");
|
||||||
|
fflush(stdout);
|
||||||
|
fflush(stderr);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
else if (pid > 0)
|
||||||
|
{
|
||||||
|
printf("Waiting for child process %d to exit\n", pid);
|
||||||
|
int status;
|
||||||
|
waitpid(pid, &status, 0);
|
||||||
|
printf("status=%#x\n", status);
|
||||||
|
int exited = WIFEXITED(status);
|
||||||
|
if (exited)
|
||||||
|
{
|
||||||
|
int exitCode = WEXITSTATUS(status);
|
||||||
|
if (exitCode != 0)
|
||||||
|
printf("Child process exited with code: %d\n", exitCode);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Execution failed. (exited=%d, status=%#x)\n", exited, status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
perror("fork");
|
||||||
|
fflush(stdout);
|
||||||
|
fflush(stderr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_dirent()
|
||||||
|
{
|
||||||
|
printf("- Testing dirent\n");
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent *entry;
|
||||||
|
|
||||||
|
dir = opendir("/etc");
|
||||||
|
if (dir == NULL)
|
||||||
|
{
|
||||||
|
perror("opendir");
|
||||||
|
fflush(stdout);
|
||||||
|
fflush(stderr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Contents of the directory:\n");
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
while ((entry = readdir(dir)) != NULL)
|
||||||
|
{
|
||||||
|
printf("%s ", entry->d_name);
|
||||||
|
if (++i % 5 == 0)
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *create_file()
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
char *path;
|
||||||
|
|
||||||
|
if (p == NULL)
|
||||||
|
{
|
||||||
|
path = malloc(20);
|
||||||
|
sprintf(path, "/watched_file.txt");
|
||||||
|
fp = fopen(path, "w");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
path = malloc(strlen(p->pw_dir) + 20);
|
||||||
|
sprintf(path, "%s/watched_file.txt", p->pw_dir);
|
||||||
|
fp = fopen(path, "w");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fp == NULL)
|
||||||
|
{
|
||||||
|
perror("fopen");
|
||||||
|
fflush(stdout);
|
||||||
|
fflush(stderr);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *create_directory()
|
||||||
|
{
|
||||||
|
char *path;
|
||||||
|
|
||||||
|
if (p == NULL)
|
||||||
|
{
|
||||||
|
path = malloc(20);
|
||||||
|
sprintf(path, "/watched_directory");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
path = malloc(strlen(p->pw_dir) + 20);
|
||||||
|
sprintf(path, "%s/watched_directory", p->pw_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mkdir(path, 0777) < 0)
|
||||||
|
{
|
||||||
|
perror("mkdir");
|
||||||
|
fflush(stdout);
|
||||||
|
fflush(stderr);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_watch_file()
|
||||||
|
{
|
||||||
|
printf("- Testing file watching\n");
|
||||||
|
pid_t pid = fork();
|
||||||
|
if (pid < 0)
|
||||||
|
{
|
||||||
|
perror("fork");
|
||||||
|
fflush(stdout);
|
||||||
|
fflush(stderr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (pid != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
char *path = create_file();
|
||||||
|
int fd, wd;
|
||||||
|
char *buffer = malloc(BUF_LEN);
|
||||||
|
|
||||||
|
fd = inotify_init();
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
perror("inotify_init");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
wd = inotify_add_watch(fd, path,
|
||||||
|
IN_OPEN | IN_MODIFY | IN_CLOSE);
|
||||||
|
if (wd < 0)
|
||||||
|
{
|
||||||
|
perror("inotify_add_watch");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Watching for changes in file.txt...\n");
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
ssize_t len = read(fd, buffer, BUF_LEN);
|
||||||
|
if (len < 0)
|
||||||
|
{
|
||||||
|
perror("read");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct inotify_event *event = (struct inotify_event *)buffer;
|
||||||
|
if (event->mask & IN_MODIFY)
|
||||||
|
printf("File modified!\n");
|
||||||
|
else if (event->mask & IN_OPEN)
|
||||||
|
printf("File opened!\n");
|
||||||
|
else if (event->mask & IN_CLOSE)
|
||||||
|
printf("File closed!\n");
|
||||||
|
else
|
||||||
|
printf("Unknown event!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
inotify_rm_watch(fd, wd);
|
||||||
|
close(fd);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_watch_directory()
|
||||||
|
{
|
||||||
|
printf("- Testing directory watching\n");
|
||||||
|
pid_t pid = fork();
|
||||||
|
if (pid < 0)
|
||||||
|
{
|
||||||
|
perror("fork");
|
||||||
|
fflush(stdout);
|
||||||
|
fflush(stderr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (pid != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
char *path = create_directory();
|
||||||
|
int fd, wd;
|
||||||
|
char *buffer = malloc(BUF_LEN);
|
||||||
|
|
||||||
|
fd = inotify_init();
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
perror("inotify_init");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
wd = inotify_add_watch(fd, path,
|
||||||
|
IN_OPEN | IN_CREATE | IN_DELETE | IN_MODIFY);
|
||||||
|
if (wd < 0)
|
||||||
|
{
|
||||||
|
perror("inotify_add_watch");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Watching for changes in the directory...\n");
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
ssize_t len = read(fd, buffer, BUF_LEN);
|
||||||
|
if (len < 0)
|
||||||
|
{
|
||||||
|
perror("read");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct inotify_event *event = (struct inotify_event *)buffer;
|
||||||
|
if (event->mask & IN_CREATE)
|
||||||
|
printf("File created: %s\n", event->name);
|
||||||
|
else if (event->mask & IN_DELETE)
|
||||||
|
printf("File deleted: %s\n", event->name);
|
||||||
|
else if (event->mask & IN_MODIFY)
|
||||||
|
printf("File modified: %s\n", event->name);
|
||||||
|
else if (event->mask & IN_OPEN)
|
||||||
|
printf("File opened: %s\n", event->name);
|
||||||
|
else
|
||||||
|
printf("Unknown event!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
inotify_rm_watch(fd, wd);
|
||||||
|
close(fd);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void shutdown_linux()
|
||||||
|
{
|
||||||
|
printf("- Testing shutdown\n");
|
||||||
|
sync();
|
||||||
|
reboot(RB_POWER_OFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reboot_linux()
|
||||||
|
{
|
||||||
|
printf("- Testing reboot\n");
|
||||||
|
sync();
|
||||||
|
reboot(RB_AUTOBOOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void self_fork_exec()
|
||||||
|
{
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
int pid = fork();
|
||||||
|
|
||||||
|
// if (pid >= 10)
|
||||||
|
// {
|
||||||
|
// printf("[%d] Forked %d times, exiting...\n", getpid(), pid);
|
||||||
|
// kill(getpid(), SIGTERM);
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (pid != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
printf("[%d] Executing utest(%d)...\n", getpid(), getppid());
|
||||||
|
char *a[] = {"/bin/utest", "loop", NULL};
|
||||||
|
int b = execv(a[0], a);
|
||||||
|
printf("Failed to execute utest: %d\n", b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fork_bomb()
|
||||||
|
{
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
printf("[%d] Forking...\n", getpid());
|
||||||
|
int pid = fork();
|
||||||
|
if (pid != 0)
|
||||||
|
printf("[%d] Forked\n", pid);
|
||||||
|
else
|
||||||
|
printf("[%d] Child\n", getpid());
|
||||||
|
sleep(5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fork_bomb_syscall()
|
||||||
|
{
|
||||||
|
#ifdef __x86_64__
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
printf("[%d] Forking...\n", getpid());
|
||||||
|
unsigned long pid;
|
||||||
|
__asm__ __volatile__("syscall" : "=a"(pid)
|
||||||
|
: "a"(57 /* x86_64 SYS_fork */)
|
||||||
|
: "rcx", "r11", "memory");
|
||||||
|
if (pid != 0)
|
||||||
|
printf("[%ld] Forked\n", pid);
|
||||||
|
else
|
||||||
|
printf("[%d] Child\n", getpid());
|
||||||
|
sleep(5);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[], char *envp[])
|
||||||
|
{
|
||||||
|
if (argv[1] != NULL && strcmp(argv[1], "loop") == 0)
|
||||||
|
{
|
||||||
|
printf("[%d] Looping...\n", getpid());
|
||||||
|
while (1)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("- Testing userspace...\n");
|
||||||
|
|
||||||
|
// printf("Press RETURN to start tests...\n");
|
||||||
|
// char key = 0;
|
||||||
|
// while (key != '\n' && key != '\r')
|
||||||
|
// key = getchar();
|
||||||
|
|
||||||
|
// self_fork_exec();
|
||||||
|
// fork_bomb();
|
||||||
|
// fork_bomb_syscall();
|
||||||
|
|
||||||
|
test_passwd();
|
||||||
|
test_brk();
|
||||||
|
test_time();
|
||||||
|
test_signal();
|
||||||
|
test_ptmx();
|
||||||
|
test_args(argc, argv, envp);
|
||||||
|
// test_stdio();
|
||||||
|
test_system();
|
||||||
|
test_file();
|
||||||
|
test_dirent();
|
||||||
|
test_execve_fork();
|
||||||
|
test_watch_file();
|
||||||
|
test_watch_directory();
|
||||||
|
// shutdown_linux();
|
||||||
|
// reboot_linux();
|
||||||
|
|
||||||
|
int status = 0;
|
||||||
|
pid_t wpid;
|
||||||
|
|
||||||
|
printf("Waiting for child processes to exit...\n");
|
||||||
|
while ((wpid = wait(&status)) > 0)
|
||||||
|
sleep(2);
|
||||||
|
|
||||||
|
sync();
|
||||||
|
printf("Userspace tests complete!\n");
|
||||||
|
|
||||||
|
pid_t pid = fork();
|
||||||
|
if (pid < 0)
|
||||||
|
{
|
||||||
|
perror("fork");
|
||||||
|
fflush(stdout);
|
||||||
|
fflush(stderr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (pid == 0)
|
||||||
|
{
|
||||||
|
printf("Starting utest_linux...\n");
|
||||||
|
char *args[] = {"/bin/utest_linux", NULL};
|
||||||
|
int ret = execv(args[0], args);
|
||||||
|
perror("execv");
|
||||||
|
fflush(stdout);
|
||||||
|
fflush(stderr);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
waitpid(pid, &status, 0);
|
||||||
|
|
||||||
|
// check if exited normally, or crashed
|
||||||
|
if (WIFSIGNALED(status))
|
||||||
|
{
|
||||||
|
int signal = WTERMSIG(status);
|
||||||
|
printf("utest_linux exited with signal: %s\n", strsignal(signal));
|
||||||
|
return signal;
|
||||||
|
}
|
||||||
|
else if (WIFEXITED(status))
|
||||||
|
{
|
||||||
|
int exitCode = WEXITSTATUS(status);
|
||||||
|
if (exitCode != 0)
|
||||||
|
{
|
||||||
|
printf("utest_linux exited with code: %d\n", exitCode);
|
||||||
|
return exitCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("utest_linux exited abnormally\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
@ -1,69 +0,0 @@
|
|||||||
#ifndef __FENNIX_LIBC_AUX_H__
|
|
||||||
#define __FENNIX_LIBC_AUX_H__
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#define AT_NULL 0
|
|
||||||
#define AT_IGNORE 1
|
|
||||||
#define AT_EXECFD 2
|
|
||||||
#define AT_PHDR 3
|
|
||||||
#define AT_PHENT 4
|
|
||||||
#define AT_PHNUM 5
|
|
||||||
#define AT_PAGESZ 6
|
|
||||||
#define AT_BASE 7
|
|
||||||
#define AT_FLAGS 8
|
|
||||||
#define AT_ENTRY 9
|
|
||||||
#define AT_NOTELF 10
|
|
||||||
#define AT_UID 11
|
|
||||||
#define AT_EUID 12
|
|
||||||
#define AT_GID 13
|
|
||||||
#define AT_EGID 14
|
|
||||||
#define AT_PLATFORM 15
|
|
||||||
#define AT_HWCAP 16
|
|
||||||
#define AT_CLKTCK 17
|
|
||||||
#define AT_SECURE 23
|
|
||||||
#define AT_BASE_PLATFORM 24
|
|
||||||
#define AT_RANDOM 25
|
|
||||||
#define AT_HWCAP2 26
|
|
||||||
#define AT_EXECFN 31
|
|
||||||
#define AT_SYSINFO 32
|
|
||||||
#define AT_SYSINFO_EHDR 33
|
|
||||||
#define AT_L1I_CACHESHAPE 34
|
|
||||||
#define AT_L1D_CACHESHAPE 35
|
|
||||||
#define AT_L2_CACHESHAPE 36
|
|
||||||
#define AT_L3_CACHESHAPE 37
|
|
||||||
#define AT_L1I_CACHESIZE 40
|
|
||||||
#define AT_L1I_CACHEGEOMETRY 41
|
|
||||||
#define AT_L1D_CACHESIZE 42
|
|
||||||
#define AT_L1D_CACHEGEOMETRY 43
|
|
||||||
#define AT_L2_CACHESIZE 44
|
|
||||||
#define AT_L2_CACHEGEOMETRY 45
|
|
||||||
#define AT_L3_CACHESIZE 46
|
|
||||||
#define AT_L3_CACHEGEOMETRY 47
|
|
||||||
#define AT_MINSIGSTKSZ 51
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint32_t a_type;
|
|
||||||
union
|
|
||||||
{
|
|
||||||
uint32_t a_val;
|
|
||||||
} a_un;
|
|
||||||
} Elf32_auxv_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint64_t a_type;
|
|
||||||
union
|
|
||||||
{
|
|
||||||
uint64_t a_val;
|
|
||||||
} a_un;
|
|
||||||
} Elf64_auxv_t;
|
|
||||||
|
|
||||||
#ifdef __LP64__
|
|
||||||
#define Elf_auxv_t Elf64_auxv_t
|
|
||||||
#else
|
|
||||||
#define Elf_auxv_t Elf32_auxv_t
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // !__FENNIX_LIBC_AUX_H__
|
|
@ -1,103 +1,6 @@
|
|||||||
#include <sys/wait.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "aux.h"
|
|
||||||
|
|
||||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
int main(int, char *[], char *[])
|
||||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
|
||||||
|
|
||||||
void test_args(int argc, char *argv[], char *envp[])
|
|
||||||
{
|
{
|
||||||
printf("%p %p %p\n", (void *)(uint64_t)&argc, (void *)&argv, (void *)&envp);
|
|
||||||
printf("I have %d arguments\n", argc);
|
|
||||||
for (int i = 0; i < argc; i++)
|
|
||||||
printf("argv[%d] = (%p) %s\n", i, argv[i], argv[i]);
|
|
||||||
|
|
||||||
int envc = 0;
|
|
||||||
while (envp[envc] != NULL)
|
|
||||||
envc++;
|
|
||||||
|
|
||||||
printf("I have %d environment variables\n", envc);
|
|
||||||
for (int i = 0; i < envc; i++)
|
|
||||||
printf("envp[%d] = (%p) %s\n", i, envp[i], envp[i]);
|
|
||||||
|
|
||||||
Elf64_auxv_t *auxv;
|
|
||||||
char **e = envp;
|
|
||||||
|
|
||||||
while (*e++ != NULL)
|
|
||||||
;
|
|
||||||
|
|
||||||
for (auxv = (Elf64_auxv_t *)e; auxv->a_type != AT_NULL; auxv++)
|
|
||||||
printf("auxv: %ld %#lx\n", auxv->a_type, auxv->a_un.a_val);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[], char *envp[])
|
|
||||||
{
|
|
||||||
printf("Hello, World!\n");
|
|
||||||
// while (1);
|
|
||||||
// test_args(argc, argv, envp);
|
|
||||||
FILE *test = fopen("/test.txt", "r");
|
|
||||||
if (test == NULL)
|
|
||||||
{
|
|
||||||
printf("Failed to open file\n");
|
|
||||||
return -0xF11e;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Test.txt contents: ");
|
|
||||||
char ch;
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
ch = fgetc(test);
|
|
||||||
if (ch == EOF)
|
|
||||||
{
|
|
||||||
printf("\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
putchar(ch);
|
|
||||||
}
|
|
||||||
fclose(test);
|
|
||||||
|
|
||||||
pid_t pid = fork();
|
|
||||||
|
|
||||||
if (pid == 0) // Child process
|
|
||||||
{
|
|
||||||
pid_t pid2 = fork();
|
|
||||||
if (pid == 0) // Child process
|
|
||||||
{
|
|
||||||
char *shebang_args[] = {"/test.sh", NULL};
|
|
||||||
execv(shebang_args[0], shebang_args);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Creating shell process\n");
|
|
||||||
char *args[] = {"/bin/echo", "Hello, World!", NULL};
|
|
||||||
execv(args[0], args);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
else if (pid > 0)
|
|
||||||
{
|
|
||||||
printf("Waiting for child process %d to exit\n", pid);
|
|
||||||
int status;
|
|
||||||
wait(&status);
|
|
||||||
int exited = WIFEXITED(status);
|
|
||||||
if (exited)
|
|
||||||
{
|
|
||||||
int exit_code = WEXITSTATUS(status);
|
|
||||||
printf("Child process exited with code: %d\n", exit_code);
|
|
||||||
return exit_code;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("Execution failed. (%d)\n", exited);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("\eFF0000Failed to create the process.\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user