mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 10:48:38 +00:00
Compare commits
21 commits
d74deb0702
...
141ac8e49a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
141ac8e49a | ||
|
|
7339183bf1 | ||
|
|
7d1426de46 | ||
|
|
fdd25b31cd | ||
|
|
59c3592c21 | ||
|
|
bb57a4eeff | ||
|
|
3f19c74210 | ||
|
|
5028e0e572 | ||
|
|
05abd505ef | ||
|
|
3a295cd2f0 | ||
|
|
4f17e0787c | ||
|
|
d4522cab21 | ||
|
|
9c5cc83004 | ||
|
|
007ef4469f | ||
|
|
d8b2e3d980 | ||
|
|
a9cfab53f9 | ||
|
|
74f7710ea0 | ||
|
|
7a6769c2ec | ||
|
|
f450ba4b51 | ||
|
|
57bc840bcb | ||
|
|
e313e9dfcc |
14 changed files with 1480 additions and 616 deletions
240
Makefile
240
Makefile
|
|
@ -36,43 +36,21 @@ USERLAND_METADATA_ICONS = $(shell { \
|
||||||
} | tr ';' '\n' | sed 's@.*/@@' | sed '/^[[:space:]]*$$/d' | sort -u)
|
} | tr ';' '\n' | sed 's@.*/@@' | sed '/^[[:space:]]*$$/d' | sort -u)
|
||||||
COLLOID_ICONS = $(sort $(DOCK_COLLOID_ICONS) $(USERLAND_COLLOID_ICONS) $(USERLAND_METADATA_ICONS) xterm.png)
|
COLLOID_ICONS = $(sort $(DOCK_COLLOID_ICONS) $(USERLAND_COLLOID_ICONS) $(USERLAND_METADATA_ICONS) xterm.png)
|
||||||
|
|
||||||
C_SOURCES = $(wildcard $(SRC_DIR)/core/*.c) \
|
C_SOURCES := $(shell find $(SRC_DIR) -type f -name '*.c' \
|
||||||
$(wildcard $(SRC_DIR)/sys/*.c) \
|
! -path '$(SRC_DIR)/userland/*' \
|
||||||
$(wildcard $(SRC_DIR)/mem/*.c) \
|
! -path '*/third_party/lwip/netif/slipif.c')
|
||||||
$(wildcard $(SRC_DIR)/dev/*.c) \
|
ASM_SOURCES := $(shell find $(SRC_DIR) -type f -name '*.asm' ! -path '$(SRC_DIR)/userland/*')
|
||||||
$(wildcard $(SRC_DIR)/drivers/*.c) \
|
|
||||||
$(wildcard $(SRC_DIR)/input/*.c) \
|
|
||||||
$(wildcard $(SRC_DIR)/net/*.c) \
|
|
||||||
$(wildcard $(SRC_DIR)/net/nic/*.c) \
|
|
||||||
$(wildcard $(SRC_DIR)/fs/*.c) \
|
|
||||||
$(wildcard $(SRC_DIR)/wm/*.c) \
|
|
||||||
$(wildcard $(SRC_DIR)/net/third_party/lwip/core/*.c) \
|
|
||||||
$(wildcard $(SRC_DIR)/net/third_party/lwip/core/ipv4/*.c) \
|
|
||||||
$(SRC_DIR)/net/third_party/lwip/netif/ethernet.c \
|
|
||||||
$(SRC_DIR)/net/third_party/lwip/netif/bridgeif.c
|
|
||||||
|
|
||||||
ASM_SOURCES = $(wildcard $(SRC_DIR)/arch/*.asm)
|
OBJ_FILES := $(patsubst $(SRC_DIR)/%.c, $(BUILD_DIR)/%.o, $(C_SOURCES)) \
|
||||||
OBJ_FILES = $(patsubst $(SRC_DIR)/core/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/core/*.c)) \
|
$(patsubst $(SRC_DIR)/%.asm, $(BUILD_DIR)/%.o, $(ASM_SOURCES))
|
||||||
$(patsubst $(SRC_DIR)/sys/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/sys/*.c)) \
|
|
||||||
$(patsubst $(SRC_DIR)/mem/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/mem/*.c)) \
|
INCLUDE_DIRS := $(shell find $(SRC_DIR) -type d ! -path '$(SRC_DIR)/userland*')
|
||||||
$(patsubst $(SRC_DIR)/dev/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/dev/*.c)) \
|
INCLUDES := $(patsubst %, -I%, $(INCLUDE_DIRS))
|
||||||
$(patsubst $(SRC_DIR)/drivers/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/drivers/*.c)) \
|
|
||||||
$(patsubst $(SRC_DIR)/input/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/input/*.c)) \
|
|
||||||
$(patsubst $(SRC_DIR)/net/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/net/*.c)) \
|
|
||||||
$(patsubst $(SRC_DIR)/net/nic/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/net/nic/*.c)) \
|
|
||||||
$(patsubst $(SRC_DIR)/fs/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/fs/*.c)) \
|
|
||||||
$(patsubst $(SRC_DIR)/wm/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/wm/*.c)) \
|
|
||||||
$(patsubst $(SRC_DIR)/net/third_party/lwip/%.c, $(BUILD_DIR)/lwip/%.o, $(filter $(SRC_DIR)/net/third_party/lwip/%.c, $(C_SOURCES))) \
|
|
||||||
$(patsubst $(SRC_DIR)/arch/%.asm, $(BUILD_DIR)/%.o, $(ASM_SOURCES))
|
|
||||||
|
|
||||||
CFLAGS = -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding \
|
CFLAGS = -g -O2 -pipe -Wall -Wextra -std=gnu11 -ffreestanding \
|
||||||
-fno-stack-protector -fno-stack-check -fno-lto -fPIE \
|
-fno-stack-protector -fno-stack-check -fno-lto -fPIE \
|
||||||
-m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone \
|
-m64 -march=x86-64 -msse -msse2 -mstackrealign -mno-red-zone \
|
||||||
-I$(SRC_DIR) -I$(SRC_DIR)/net/third_party/lwip -I$(SRC_DIR)/core \
|
$(INCLUDES)
|
||||||
-I$(SRC_DIR)/sys -I$(SRC_DIR)/mem -I$(SRC_DIR)/dev \
|
|
||||||
-I$(SRC_DIR)/drivers \
|
|
||||||
-I$(SRC_DIR)/net -I$(SRC_DIR)/net/nic -I$(SRC_DIR)/fs \
|
|
||||||
-I$(SRC_DIR)/wm -I$(SRC_DIR)/input
|
|
||||||
|
|
||||||
LDFLAGS = -m elf_x86_64 -nostdlib -static -pie --no-dynamic-linker \
|
LDFLAGS = -m elf_x86_64 -nostdlib -static -pie --no-dynamic-linker \
|
||||||
-z text -z max-page-size=0x1000 -T linker.ld
|
-z text -z max-page-size=0x1000 -T linker.ld
|
||||||
|
|
@ -94,118 +72,52 @@ all:
|
||||||
$(BUILD_DIR):
|
$(BUILD_DIR):
|
||||||
$(call PRINT_STEP,CREATING BUILD DIRECTORY)
|
$(call PRINT_STEP,CREATING BUILD DIRECTORY)
|
||||||
mkdir -p $(BUILD_DIR)
|
mkdir -p $(BUILD_DIR)
|
||||||
mkdir -p $(BUILD_DIR)
|
|
||||||
|
|
||||||
limine-setup:
|
limine-setup:
|
||||||
$(call PRINT_STEP,SETTING UP LIMINE)
|
$(call PRINT_STEP,SETTING UP LIMINE)
|
||||||
@if [ ! -f limine/limine-bios.sys ]; then \
|
@if [ ! -f limine/limine-bios.sys ]; then \
|
||||||
printf "$(YELLOW)[LIMINE] Limine binaries missing or invalid. Cloning v$(LIMINE_VERSION)-binary...$(RESET)"; \
|
printf "$(YELLOW)[LIMINE] Limine binaries missing or invalid. Cloning v$(LIMINE_VERSION)-binary...$(RESET)\n"; \
|
||||||
rm -rf limine; \
|
rm -rf limine; \
|
||||||
git clone https://github.com/limine-bootloader/limine.git --branch=v$(LIMINE_VERSION)-binary --depth=1 limine; \
|
git clone https://github.com/limine-bootloader/limine.git --branch=v$(LIMINE_VERSION)-binary --depth=1 limine; \
|
||||||
else \
|
else \
|
||||||
printf "$(YELLOW)[LIMINE] Existing Limine binaries found.$(RESET)"; \
|
printf "$(YELLOW)[LIMINE] Existing Limine binaries found.$(RESET)\n"; \
|
||||||
fi
|
fi
|
||||||
@if [ ! -f $(SRC_DIR)/core/limine.h ]; then \
|
@if [ ! -f $(SRC_DIR)/core/limine.h ]; then \
|
||||||
printf "$(YELLOW)[LIMINE] Copying limine.h...$(RESET)"; \
|
printf "$(YELLOW)[LIMINE] Copying limine.h...$(RESET)\n"; \
|
||||||
cp limine/limine.h $(SRC_DIR)/core/limine.h; \
|
cp limine/limine.h $(SRC_DIR)/core/limine.h; \
|
||||||
else \
|
else \
|
||||||
printf "$(YELLOW)[LIMINE] limine.h already present.$(RESET)"; \
|
printf "$(YELLOW)[LIMINE] limine.h already present.$(RESET)\n"; \
|
||||||
fi
|
fi
|
||||||
@printf "$(YELLOW)[LIMINE] Building Limine host utility...$(RESET)"
|
@printf "$(YELLOW)[LIMINE] Building Limine host utility...$(RESET)\n"
|
||||||
$(MAKE) -C limine
|
$(MAKE) -C limine
|
||||||
@printf "$(GREEN)[OK] Limine setup complete.$(RESET)"
|
@printf "$(GREEN)[OK] Limine setup complete.$(RESET)\n"
|
||||||
|
|
||||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c | $(BUILD_DIR) limine-setup
|
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c | $(BUILD_DIR) limine-setup
|
||||||
@printf "$(YELLOW)[CC]$(RESET) $< -> $@"
|
@printf "$(YELLOW)[CC]$(RESET) $< -> $@\n"
|
||||||
mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/core/%.c | $(BUILD_DIR) limine-setup
|
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.asm | $(BUILD_DIR)
|
||||||
@printf "$(YELLOW)[CC]$(RESET)[core] $< -> $@"
|
@printf "$(YELLOW)[ASM]$(RESET) $< -> $@\n"
|
||||||
mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
|
||||||
|
|
||||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/sys/%.c | $(BUILD_DIR) limine-setup
|
|
||||||
@printf "$(YELLOW)[CC]$(RESET)[sys] $< -> $@"
|
|
||||||
mkdir -p $(dir $@)
|
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
|
||||||
|
|
||||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/mem/%.c | $(BUILD_DIR) limine-setup
|
|
||||||
@printf "$(YELLOW)[CC]$(RESET)[mem] $< -> $@"
|
|
||||||
mkdir -p $(dir $@)
|
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
|
||||||
|
|
||||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/dev/%.c | $(BUILD_DIR) limine-setup
|
|
||||||
@printf "$(YELLOW)[CC]$(RESET)[dev] $< -> $@"
|
|
||||||
mkdir -p $(dir $@)
|
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
|
||||||
|
|
||||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/drivers/%.c | $(BUILD_DIR) limine-setup
|
|
||||||
@printf "$(YELLOW)[CC]$(RESET)[drivers] $< -> $@"
|
|
||||||
mkdir -p $(dir $@)
|
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
|
||||||
|
|
||||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/input/%.c | $(BUILD_DIR) limine-setup
|
|
||||||
@printf "$(YELLOW)[CC]$(RESET)[input] $< -> $@"
|
|
||||||
mkdir -p $(dir $@)
|
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
|
||||||
|
|
||||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/net/%.c | $(BUILD_DIR) limine-setup
|
|
||||||
@printf "$(YELLOW)[CC]$(RESET)[net] $< -> $@"
|
|
||||||
mkdir -p $(dir $@)
|
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
|
||||||
|
|
||||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/net/nic/%.c | $(BUILD_DIR) limine-setup
|
|
||||||
@printf "$(YELLOW)[CC]$(RESET)[net/nic] $< -> $@"
|
|
||||||
mkdir -p $(dir $@)
|
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
|
||||||
|
|
||||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/fs/%.c | $(BUILD_DIR) limine-setup
|
|
||||||
@printf "$(YELLOW)[CC]$(RESET)[fs] $< -> $@"
|
|
||||||
mkdir -p $(dir $@)
|
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
|
||||||
|
|
||||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/wm/%.c | $(BUILD_DIR) limine-setup
|
|
||||||
@printf "$(YELLOW)[CC]$(RESET)[wm] $< -> $@"
|
|
||||||
mkdir -p $(dir $@)
|
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
|
||||||
|
|
||||||
$(BUILD_DIR)/lwip/%.o: $(SRC_DIR)/net/third_party/lwip/%.c | $(BUILD_DIR) limine-setup
|
|
||||||
@printf "$(YELLOW)[CC]$(RESET)[lwIP] $< -> $@"
|
|
||||||
mkdir -p $(dir $@)
|
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
|
||||||
|
|
||||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/arch/%.asm | $(BUILD_DIR)
|
|
||||||
@printf "$(YELLOW)[ASM]$(RESET) $< -> $@"
|
|
||||||
$(NASM) $(NASMFLAGS) $< -o $@
|
$(NASM) $(NASMFLAGS) $< -o $@
|
||||||
|
|
||||||
$(BUILD_DIR)/test_syscall.o: $(SRC_DIR)/arch/test_syscall.asm | $(BUILD_DIR)
|
|
||||||
@printf "$(YELLOW)[ASM][test_syscall]$(RESET) $< -> $@"
|
|
||||||
$(NASM) $(NASMFLAGS) $< -o $@
|
|
||||||
|
|
||||||
$(BUILD_DIR)/user_test.o: $(SRC_DIR)/arch/user_test.asm | $(BUILD_DIR)
|
|
||||||
@printf "$(YELLOW)[ASM][user_test]$(RESET) $< -> $@"
|
|
||||||
$(NASM) $(NASMFLAGS) $< -o $@
|
|
||||||
|
|
||||||
$(BUILD_DIR)/process_asm.o: $(SRC_DIR)/arch/process_asm.asm | $(BUILD_DIR)
|
|
||||||
@printf "$(YELLOW)[ASM][process]$(RESET) $< -> $@"
|
|
||||||
$(NASM) $(NASMFLAGS) $< -o $@
|
|
||||||
|
|
||||||
$(KERNEL_ELF): $(OBJ_FILES)
|
$(KERNEL_ELF): $(OBJ_FILES)
|
||||||
$(call PRINT_STEP,LINKING KERNEL)
|
$(call PRINT_STEP,LINKING KERNEL)
|
||||||
@printf "$(YELLOW)[LD]$(RESET) Linking kernel ELF: $@"
|
@printf "$(YELLOW)[LD]$(RESET) Linking kernel ELF: $@\n"
|
||||||
$(LD) $(LDFLAGS) -o $@ $(OBJ_FILES)
|
$(LD) $(LDFLAGS) -o $@ $(OBJ_FILES)
|
||||||
@printf "$(GREEN)[OK]$(RESET) Kernel ELF built: $@"
|
@printf "$(GREEN)[OK]$(RESET) Kernel ELF built: $@\n"
|
||||||
$(call PRINT_STEP,BUILDING USERLAND)
|
$(call PRINT_STEP,BUILDING USERLAND)
|
||||||
$(MAKE) -C $(SRC_DIR)/userland
|
$(MAKE) -C $(SRC_DIR)/userland
|
||||||
@printf "$(GREEN)[OK]$(RESET) Userland build complete."
|
@printf "$(GREEN)[OK]$(RESET) Userland build complete.\n"
|
||||||
|
|
||||||
$(BUILD_DIR)/initrd.tar: $(KERNEL_ELF)
|
$(BUILD_DIR)/initrd.tar: $(KERNEL_ELF)
|
||||||
$(call PRINT_STEP,BUILDING INITRD)
|
$(call PRINT_STEP,BUILDING INITRD)
|
||||||
@printf "$(YELLOW)[INITRD]$(RESET) Cleaning previous initrd directory..."
|
@printf "$(YELLOW)[INITRD]$(RESET) Cleaning previous initrd directory...\n"
|
||||||
rm -rf $(BUILD_DIR)/initrd
|
rm -rf $(BUILD_DIR)/initrd
|
||||||
|
|
||||||
@printf "$(YELLOW)[INITRD]$(RESET) Creating directory structure..."
|
@printf "$(YELLOW)[INITRD]$(RESET) Creating directory structure...\n"
|
||||||
mkdir -p $(BUILD_DIR)/initrd/bin
|
mkdir -p $(BUILD_DIR)/initrd/bin
|
||||||
mkdir -p $(BUILD_DIR)/initrd/Library/images/Wallpapers
|
mkdir -p $(BUILD_DIR)/initrd/Library/images/Wallpapers
|
||||||
mkdir -p $(BUILD_DIR)/initrd/Library/images/gif
|
mkdir -p $(BUILD_DIR)/initrd/Library/images/gif
|
||||||
|
|
@ -232,21 +144,21 @@ $(BUILD_DIR)/initrd.tar: $(KERNEL_ELF)
|
||||||
mkdir -p $(BUILD_DIR)/initrd/usr/include/libc
|
mkdir -p $(BUILD_DIR)/initrd/usr/include/libc
|
||||||
mkdir -p $(BUILD_DIR)/initrd/usr/lib
|
mkdir -p $(BUILD_DIR)/initrd/usr/lib
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) Limine binaries + kernel for installer..."
|
@printf "$(YELLOW)[COPY]$(RESET) Limine binaries + kernel for installer...\n"
|
||||||
@if [ -f limine/BOOTX64.EFI ]; then cp limine/BOOTX64.EFI $(BUILD_DIR)/initrd/boot/; fi
|
@if [ -f limine/BOOTX64.EFI ]; then cp limine/BOOTX64.EFI $(BUILD_DIR)/initrd/boot/; fi
|
||||||
@if [ -f limine/BOOTIA32.EFI ]; then cp limine/BOOTIA32.EFI $(BUILD_DIR)/initrd/boot/; fi
|
@if [ -f limine/BOOTIA32.EFI ]; then cp limine/BOOTIA32.EFI $(BUILD_DIR)/initrd/boot/; fi
|
||||||
@if [ -f limine/limine-bios.sys ]; then cp limine/limine-bios.sys $(BUILD_DIR)/initrd/boot/; fi
|
@if [ -f limine/limine-bios.sys ]; then cp limine/limine-bios.sys $(BUILD_DIR)/initrd/boot/; fi
|
||||||
@cp $(KERNEL_ELF) $(BUILD_DIR)/initrd/boot/boredos.elf
|
@cp $(KERNEL_ELF) $(BUILD_DIR)/initrd/boot/boredos.elf
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) Userland binaries..."
|
@printf "$(YELLOW)[COPY]$(RESET) Userland binaries...\n"
|
||||||
@for f in $(SRC_DIR)/userland/bin/*.elf; do \
|
@for f in $(SRC_DIR)/userland/bin/*.elf; do \
|
||||||
if [ -f "$$f" ]; then \
|
if [ -f "$$f" ]; then \
|
||||||
printf " -> $$f"; \
|
printf " -> $$f\n"; \
|
||||||
cp "$$f" $(BUILD_DIR)/initrd/bin/; \
|
cp "$$f" $(BUILD_DIR)/initrd/bin/; \
|
||||||
fi \
|
fi \
|
||||||
done
|
done
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) TCC support files..."
|
@printf "$(YELLOW)[COPY]$(RESET) TCC support files...\n"
|
||||||
@cp $(SRC_DIR)/userland/cli/third_party/tcc/libtcc1.a $(BUILD_DIR)/initrd/usr/lib/tcc/
|
@cp $(SRC_DIR)/userland/cli/third_party/tcc/libtcc1.a $(BUILD_DIR)/initrd/usr/lib/tcc/
|
||||||
@cp $(SRC_DIR)/userland/cli/third_party/tcc/libtcc1.a $(BUILD_DIR)/initrd/usr/lib/
|
@cp $(SRC_DIR)/userland/cli/third_party/tcc/libtcc1.a $(BUILD_DIR)/initrd/usr/lib/
|
||||||
@cp $(SRC_DIR)/userland/cli/third_party/tcc/include/*.h $(BUILD_DIR)/initrd/usr/lib/tcc/include/
|
@cp $(SRC_DIR)/userland/cli/third_party/tcc/include/*.h $(BUILD_DIR)/initrd/usr/lib/tcc/include/
|
||||||
|
|
@ -263,120 +175,120 @@ $(BUILD_DIR)/initrd.tar: $(KERNEL_ELF)
|
||||||
@cp $(SRC_DIR)/userland/libc/*.h $(BUILD_DIR)/initrd/usr/local/include/
|
@cp $(SRC_DIR)/userland/libc/*.h $(BUILD_DIR)/initrd/usr/local/include/
|
||||||
@cp $(SRC_DIR)/userland/stb_image.h $(BUILD_DIR)/initrd/usr/include/
|
@cp $(SRC_DIR)/userland/stb_image.h $(BUILD_DIR)/initrd/usr/include/
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) Wallpapers..."
|
@printf "$(YELLOW)[COPY]$(RESET) Wallpapers...\n"
|
||||||
@for f in $(SRC_DIR)/images/wallpapers/*; do \
|
@for f in $(SRC_DIR)/images/wallpapers/*; do \
|
||||||
if [ -f "$$f" ]; then \
|
if [ -f "$$f" ]; then \
|
||||||
printf " -> $$f"; \
|
printf " -> $$f\n"; \
|
||||||
cp "$$f" $(BUILD_DIR)/initrd/Library/images/Wallpapers/; \
|
cp "$$f" $(BUILD_DIR)/initrd/Library/images/Wallpapers/; \
|
||||||
fi \
|
fi \
|
||||||
done
|
done
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) GIF assets..."
|
@printf "$(YELLOW)[COPY]$(RESET) GIF assets...\n"
|
||||||
@for f in $(SRC_DIR)/images/gif/*.gif; do \
|
@for f in $(SRC_DIR)/images/gif/*.gif; do \
|
||||||
if [ -f "$$f" ]; then \
|
if [ -f "$$f" ]; then \
|
||||||
printf " -> $$f"; \
|
printf " -> $$f\n"; \
|
||||||
cp "$$f" $(BUILD_DIR)/initrd/Library/images/gif/; \
|
cp "$$f" $(BUILD_DIR)/initrd/Library/images/gif/; \
|
||||||
fi \
|
fi \
|
||||||
done
|
done
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) Colloid icons..."
|
@printf "$(YELLOW)[COPY]$(RESET) Colloid icons...\n"
|
||||||
@for f in $(COLLOID_ICONS); do \
|
@for f in $(COLLOID_ICONS); do \
|
||||||
src="$(SRC_DIR)/images/icons/colloid/$$f"; \
|
src="$(SRC_DIR)/images/icons/colloid/$$f"; \
|
||||||
if [ -f "$$src" ]; then \
|
if [ -f "$$src" ]; then \
|
||||||
printf " -> $$src"; \
|
printf " -> $$src\n"; \
|
||||||
cp "$$src" $(BUILD_DIR)/initrd/Library/images/icons/colloid/; \
|
cp "$$src" $(BUILD_DIR)/initrd/Library/images/icons/colloid/; \
|
||||||
fi \
|
fi \
|
||||||
done
|
done
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) BoredOS icons..."
|
@printf "$(YELLOW)[COPY]$(RESET) BoredOS icons...\n"
|
||||||
@mkdir -p $(BUILD_DIR)/initrd/Library/images/icons/boredos
|
@mkdir -p $(BUILD_DIR)/initrd/Library/images/icons/boredos
|
||||||
@for f in $(SRC_DIR)/images/icons/boredos/*.png; do \
|
@for f in $(SRC_DIR)/images/icons/boredos/*.png; do \
|
||||||
if [ -f "$$f" ]; then \
|
if [ -f "$$f" ]; then \
|
||||||
printf " -> $$f"; \
|
printf " -> $$f\n"; \
|
||||||
cp "$$f" $(BUILD_DIR)/initrd/Library/images/icons/boredos/; \
|
cp "$$f" $(BUILD_DIR)/initrd/Library/images/icons/boredos/; \
|
||||||
fi \
|
fi \
|
||||||
done
|
done
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) Branding assets..."
|
@printf "$(YELLOW)[COPY]$(RESET) Branding assets...\n"
|
||||||
@cp -r branding/* $(BUILD_DIR)/initrd/Library/images/branding/
|
@cp -r branding/* $(BUILD_DIR)/initrd/Library/images/branding/
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) Fonts..."
|
@printf "$(YELLOW)[COPY]$(RESET) Fonts...\n"
|
||||||
@for f in $(SRC_DIR)/fonts/*.ttf; do \
|
@for f in $(SRC_DIR)/fonts/*.ttf; do \
|
||||||
if [ -f "$$f" ]; then \
|
if [ -f "$$f" ]; then \
|
||||||
printf " -> $$f"; \
|
printf " -> $$f\n"; \
|
||||||
cp "$$f" $(BUILD_DIR)/initrd/Library/Fonts/; \
|
cp "$$f" $(BUILD_DIR)/initrd/Library/Fonts/; \
|
||||||
fi \
|
fi \
|
||||||
done
|
done
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) Emoji fonts..."
|
@printf "$(YELLOW)[COPY]$(RESET) Emoji fonts...\n"
|
||||||
@for f in $(SRC_DIR)/fonts/Emoji/*.ttf; do \
|
@for f in $(SRC_DIR)/fonts/Emoji/*.ttf; do \
|
||||||
if [ -f "$$f" ]; then \
|
if [ -f "$$f" ]; then \
|
||||||
printf " -> $$f"; \
|
printf " -> $$f\n"; \
|
||||||
cp "$$f" $(BUILD_DIR)/initrd/Library/Fonts/Emoji/; \
|
cp "$$f" $(BUILD_DIR)/initrd/Library/Fonts/Emoji/; \
|
||||||
fi \
|
fi \
|
||||||
done
|
done
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) bsh configuration..."
|
@printf "$(YELLOW)[COPY]$(RESET) bsh configuration...\n"
|
||||||
@if [ -f $(SRC_DIR)/library/bsh/bshrc ]; then printf " -> bshrc"; cp $(SRC_DIR)/library/bsh/bshrc $(BUILD_DIR)/initrd/Library/bsh/; fi
|
@if [ -f $(SRC_DIR)/library/bsh/bshrc ]; then printf " -> bshrc\n"; cp $(SRC_DIR)/library/bsh/bshrc $(BUILD_DIR)/initrd/Library/bsh/; fi
|
||||||
@if [ -f $(SRC_DIR)/library/bsh/startup.bsh ]; then printf " -> startup.bsh"; cp $(SRC_DIR)/library/bsh/startup.bsh $(BUILD_DIR)/initrd/Library/bsh/; fi
|
@if [ -f $(SRC_DIR)/library/bsh/startup.bsh ]; then printf " -> startup.bsh\n"; cp $(SRC_DIR)/library/bsh/startup.bsh $(BUILD_DIR)/initrd/Library/bsh/; fi
|
||||||
@if [ -f $(SRC_DIR)/library/bsh/boot.bsh ]; then printf " -> boot.bsh"; cp $(SRC_DIR)/library/bsh/boot.bsh $(BUILD_DIR)/initrd/Library/bsh/; fi
|
@if [ -f $(SRC_DIR)/library/bsh/boot.bsh ]; then printf " -> boot.bsh\n"; cp $(SRC_DIR)/library/bsh/boot.bsh $(BUILD_DIR)/initrd/Library/bsh/; fi
|
||||||
@if [ -f $(SRC_DIR)/library/conf/sysfetch.cfg ]; then printf " -> sysfetch.cfg"; cp $(SRC_DIR)/library/conf/sysfetch.cfg $(BUILD_DIR)/initrd/Library/conf/; fi
|
@if [ -f $(SRC_DIR)/library/conf/sysfetch.cfg ]; then printf " -> sysfetch.cfg\n"; cp $(SRC_DIR)/library/conf/sysfetch.cfg $(BUILD_DIR)/initrd/Library/conf/; fi
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) DOOM assets..."
|
@printf "$(YELLOW)[COPY]$(RESET) DOOM assets...\n"
|
||||||
@if [ -f $(SRC_DIR)/userland/games/doom/doom1.wad ]; then printf " -> doom1.wad"; cp $(SRC_DIR)/userland/games/doom/doom1.wad $(BUILD_DIR)/initrd/Library/DOOM/; fi
|
@if [ -f $(SRC_DIR)/userland/games/doom/doom1.wad ]; then printf " -> doom1.wad\n"; cp $(SRC_DIR)/userland/games/doom/doom1.wad $(BUILD_DIR)/initrd/Library/DOOM/; fi
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) ASCII art..."
|
@printf "$(YELLOW)[COPY]$(RESET) ASCII art...\n"
|
||||||
@if [ -f $(SRC_DIR)/library/art/boredos.txt ]; then printf " -> boredos.txt"; cp $(SRC_DIR)/library/art/boredos.txt $(BUILD_DIR)/initrd/Library/art/; fi
|
@if [ -f $(SRC_DIR)/library/art/boredos.txt ]; then printf " -> boredos.txt\n"; cp $(SRC_DIR)/library/art/boredos.txt $(BUILD_DIR)/initrd/Library/art/; fi
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) Documentation..."
|
@printf "$(YELLOW)[COPY]$(RESET) Documentation...\n"
|
||||||
@for f in $$(find docs -name '*.md' 2>/dev/null); do \
|
@for f in $$(find docs -name '*.md' 2>/dev/null); do \
|
||||||
if [ -f "$$f" ]; then \
|
if [ -f "$$f" ]; then \
|
||||||
printf " -> $$f"; \
|
printf " -> $$f\n"; \
|
||||||
dir=$$(dirname "$$f"); \
|
dir=$$(dirname "$$f"); \
|
||||||
mkdir -p $(BUILD_DIR)/initrd/"$$dir"; \
|
mkdir -p $(BUILD_DIR)/initrd/"$$dir"; \
|
||||||
cp "$$f" $(BUILD_DIR)/initrd/"$$dir"/; \
|
cp "$$f" $(BUILD_DIR)/initrd/"$$dir"/; \
|
||||||
fi \
|
fi \
|
||||||
done
|
done
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) Root files..."
|
@printf "$(YELLOW)[COPY]$(RESET) Root files...\n"
|
||||||
@if [ -f README.md ]; then printf " -> README.md"; cp README.md $(BUILD_DIR)/initrd/; fi
|
@if [ -f README.md ]; then printf " -> README.md\n"; cp README.md $(BUILD_DIR)/initrd/; fi
|
||||||
@if [ -f LICENSE ]; then printf " -> LICENSE"; cp LICENSE $(BUILD_DIR)/initrd/; fi
|
@if [ -f LICENSE ]; then printf " -> LICENSE\n"; cp LICENSE $(BUILD_DIR)/initrd/; fi
|
||||||
@if [ -f limine.conf ]; then printf " -> limine.conf"; cp limine.conf $(BUILD_DIR)/initrd/; fi
|
@if [ -f limine.conf ]; then printf " -> limine.conf\n"; cp limine.conf $(BUILD_DIR)/initrd/; fi
|
||||||
|
|
||||||
@printf "$(YELLOW)[TAR]$(RESET) Creating initrd.tar..."
|
@printf "$(YELLOW)[TAR]$(RESET) Creating initrd.tar...\n"
|
||||||
cd $(BUILD_DIR)/initrd && COPYFILE_DISABLE=1 tar --exclude="._*" -cf ../initrd.tar *
|
cd $(BUILD_DIR)/initrd && COPYFILE_DISABLE=1 tar --exclude="._*" -cf ../initrd.tar *
|
||||||
@printf "$(GREEN)[OK]$(RESET) Initrd created: $(BUILD_DIR)/initrd.tar"
|
@printf "$(GREEN)[OK]$(RESET) Initrd created: $(BUILD_DIR)/initrd.tar\n"
|
||||||
|
|
||||||
$(ISO_IMAGE): $(KERNEL_ELF) $(BUILD_DIR)/initrd.tar limine.conf limine-setup
|
$(ISO_IMAGE): $(KERNEL_ELF) $(BUILD_DIR)/initrd.tar limine.conf limine-setup
|
||||||
$(call PRINT_STEP,CREATING ISO IMAGE)
|
$(call PRINT_STEP,CREATING ISO IMAGE)
|
||||||
@printf "$(YELLOW)[ISO]$(RESET) Cleaning previous ISO root..."
|
@printf "$(YELLOW)[ISO]$(RESET) Cleaning previous ISO root...\n"
|
||||||
rm -rf $(ISO_DIR)
|
rm -rf $(ISO_DIR)
|
||||||
|
|
||||||
@printf "$(YELLOW)[ISO]$(RESET) Creating ISO directory structure..."
|
@printf "$(YELLOW)[ISO]$(RESET) Creating ISO directory structure...\n"
|
||||||
mkdir -p $(ISO_DIR)
|
mkdir -p $(ISO_DIR)
|
||||||
mkdir -p $(ISO_DIR)/EFI/BOOT
|
mkdir -p $(ISO_DIR)/EFI/BOOT
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) Kernel ELF..."
|
@printf "$(YELLOW)[COPY]$(RESET) Kernel ELF...\n"
|
||||||
cp $(KERNEL_ELF) $(ISO_DIR)/
|
cp $(KERNEL_ELF) $(ISO_DIR)/
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) Limine config..."
|
@printf "$(YELLOW)[COPY]$(RESET) Limine config...\n"
|
||||||
cp limine.conf $(ISO_DIR)/
|
cp limine.conf $(ISO_DIR)/
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) Initrd..."
|
@printf "$(YELLOW)[COPY]$(RESET) Initrd...\n"
|
||||||
cp $(BUILD_DIR)/initrd.tar $(ISO_DIR)/
|
cp $(BUILD_DIR)/initrd.tar $(ISO_DIR)/
|
||||||
|
|
||||||
@printf "$(YELLOW)[CONFIG]$(RESET) Adding initrd module path..."
|
@printf "$(YELLOW)[CONFIG]$(RESET) Adding initrd module path...\n"
|
||||||
printf " module_path: boot():/initrd.tar" >> $(ISO_DIR)/limine.conf
|
printf " module_path: boot():/initrd.tar\n" >> $(ISO_DIR)/limine.conf
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) Optional splash image..."
|
@printf "$(YELLOW)[COPY]$(RESET) Optional splash image...\n"
|
||||||
@if [ -f branding/splash.jpg ]; then printf " -> splash.jpg"; cp branding/splash.jpg $(ISO_DIR)/splash.jpg; else printf " -> no splash.jpg found"; fi
|
@if [ -f branding/splash.jpg ]; then printf " -> splash.jpg\n"; cp branding/splash.jpg $(ISO_DIR)/splash.jpg; else printf " -> no splash.jpg found\n"; fi
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) Limine boot files..."
|
@printf "$(YELLOW)[COPY]$(RESET) Limine boot files...\n"
|
||||||
cp limine/limine-bios.sys $(ISO_DIR)/
|
cp limine/limine-bios.sys $(ISO_DIR)/
|
||||||
cp limine/limine-bios-cd.bin $(ISO_DIR)/
|
cp limine/limine-bios-cd.bin $(ISO_DIR)/
|
||||||
cp limine/limine-uefi-cd.bin $(ISO_DIR)/
|
cp limine/limine-uefi-cd.bin $(ISO_DIR)/
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) EFI bootloaders..."
|
@printf "$(YELLOW)[COPY]$(RESET) EFI bootloaders...\n"
|
||||||
cp limine/BOOTX64.EFI $(ISO_DIR)/EFI/BOOT/
|
cp limine/BOOTX64.EFI $(ISO_DIR)/EFI/BOOT/
|
||||||
cp limine/BOOTIA32.EFI $(ISO_DIR)/EFI/BOOT/
|
cp limine/BOOTIA32.EFI $(ISO_DIR)/EFI/BOOT/
|
||||||
|
|
||||||
|
|
@ -387,15 +299,15 @@ $(ISO_IMAGE): $(KERNEL_ELF) $(BUILD_DIR)/initrd.tar limine.conf limine-setup
|
||||||
-efi-boot-part --efi-boot-image --protective-msdos-label \
|
-efi-boot-part --efi-boot-image --protective-msdos-label \
|
||||||
$(ISO_DIR) -o $(ISO_IMAGE)
|
$(ISO_DIR) -o $(ISO_IMAGE)
|
||||||
|
|
||||||
@printf "$(YELLOW)[LIMINE]$(RESET) Installing BIOS bootloader..."
|
@printf "$(YELLOW)[LIMINE]$(RESET) Installing BIOS bootloader...\n"
|
||||||
./limine/limine bios-install $(ISO_IMAGE)
|
./limine/limine bios-install $(ISO_IMAGE)
|
||||||
@printf "$(GREEN)[OK]$(RESET) ISO image ready: $(ISO_IMAGE)"
|
@printf "$(GREEN)[OK]$(RESET) ISO image ready: $(ISO_IMAGE)\n"
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(call PRINT_STEP,CLEANING BUILD OUTPUT)
|
$(call PRINT_STEP,CLEANING BUILD OUTPUT)
|
||||||
rm -rf $(BUILD_DIR) $(ISO_DIR) $(ISO_IMAGE)
|
rm -rf $(BUILD_DIR) $(ISO_DIR) $(ISO_IMAGE)
|
||||||
$(MAKE) -C $(SRC_DIR)/userland clean
|
$(MAKE) -C $(SRC_DIR)/userland clean
|
||||||
@printf "$(GREEN)[OK]$(RESET) Clean complete."
|
@printf "$(GREEN)[OK]$(RESET) Clean complete.\n"
|
||||||
|
|
||||||
disk.qcow2:
|
disk.qcow2:
|
||||||
$(call PRINT_STEP,CREATING 10GB EXPANDABLE DISK IMAGE)
|
$(call PRINT_STEP,CREATING 10GB EXPANDABLE DISK IMAGE)
|
||||||
|
|
@ -456,7 +368,7 @@ endif
|
||||||
|
|
||||||
$(OVMF_VARS):
|
$(OVMF_VARS):
|
||||||
@if [ -f $(OVMF_VARS_TMPL) ]; then \
|
@if [ -f $(OVMF_VARS_TMPL) ]; then \
|
||||||
printf "$(YELLOW)[UEFI]$(RESET) Creating local NVRAM vars..."; \
|
printf "$(YELLOW)[UEFI]$(RESET) Creating local NVRAM vars...\n"; \
|
||||||
cp $(OVMF_VARS_TMPL) $(OVMF_VARS); \
|
cp $(OVMF_VARS_TMPL) $(OVMF_VARS); \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
||||||
169
README.md
169
README.md
|
|
@ -67,175 +67,6 @@
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Contributors
|
|
||||||
|
|
||||||
<div align="center">
|
|
||||||
<img src="branding/bOS_full_gradient_cropped.png" alt="BoredOS Logo" width="450" />
|
|
||||||
|
|
||||||
<h3>A modern x86_64 hobbyist operating system built from the ground up.</h3>
|
|
||||||
|
|
||||||
[](https://www.gnu.org/licenses/gpl-3.0)
|
|
||||||

|
|
||||||

|
|
||||||

|
|
||||||
|
|
||||||
<br />
|
|
||||||
|
|
||||||
[Docs](docs/README.md) · [Build & Run](docs/build/usage.md) · [AppDev SDK](docs/appdev/sdk_reference.md) · [Discord](https://discord.gg/J2BxWaFAgY) · [Support](https://buymeacoffee.com/boreddevhq)
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> The screenshot above may represent a previous build and is subject to change as the UI evolves.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
### Kernel and Architecture
|
|
||||||
- **Long Mode Architecture** — Native x86_64 implementation utilizing 64-bit address space and registers
|
|
||||||
- **Symmetric Multi-Processing** — Scalable multi-core support with IPI-based scheduling and synchronization
|
|
||||||
- **Advanced Memory Management** — Custom slab allocator with object pooling and efficient physical/virtual page mapping
|
|
||||||
- **Hybrid VFS Layer** — Unified filesystem interface supporting FAT32, TAR, ProcFS, and SysFS
|
|
||||||
- **Preemptive Multitasking** — Prioritized process scheduling with full context isolation
|
|
||||||
- **Hardware Abstraction** — Comprehensive driver support for PCI, AHCI, PS/2, and ACPI
|
|
||||||
|
|
||||||
### Graphical Desktop Environment
|
|
||||||
- **BoredWM** — High-performance window manager featuring window stacking, focus management, and drag-and-drop interactions
|
|
||||||
- **Typography Engine** — Integrated font manager with TrueType (TTF) support and efficient glyph caching
|
|
||||||
- **Rich Media Subsystem** — Native hardware-independent decoding for PNG, JPEG, GIF, BMP, and TGA formats
|
|
||||||
- **LibWidget Toolkit** — Native UI component library for rapid application development
|
|
||||||
|
|
||||||
### Networking Stack
|
|
||||||
- **TCP/IP Integration** — Full lwIP-based network stack featuring DHCP, DNS, and Berkeley-style sockets
|
|
||||||
- **Network Services** — Integrated support for basic web browsing and real-time network telemetry
|
|
||||||
|
|
||||||
### Application Ecosystem
|
|
||||||
| Category | Applications |
|
|
||||||
|----------|--------------|
|
|
||||||
| Productivity | Text Editor, Markdown Viewer, BoredWord Processor, Web Browser, Calculator |
|
|
||||||
| Development | TCC (Tiny C Compiler), Lua|
|
|
||||||
| System | Explorer (File Manager), Task Manager, System Monitor, Graphing Utility |
|
|
||||||
| Games | doomgeneric, Minesweeper, 2048, Snake |
|
|
||||||
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 📚 Documentation
|
|
||||||
|
|
||||||
| Guide | Description |
|
|
||||||
|-------|-------------|
|
|
||||||
| [Documentation Index](docs/README.md) | Start here! |
|
|
||||||
| [Architecture Overview](docs/architecture/README.md) | Deep dive into the kernel |
|
|
||||||
| [Building and Running](docs/build/usage.md) | Set up your build environment |
|
|
||||||
| [AppDev SDK](docs/appdev/custom_apps.md) | Build your own apps for BoredOS |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Contributors
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td align="center">
|
|
||||||
<a href="https://github.com/boreddevnl">
|
|
||||||
<img src="https://github.com/boreddevnl.png?size=80" width="60" /><br />
|
|
||||||
<sub><b>BoredDevNL</b></sub>
|
|
||||||
</a><br />
|
|
||||||
Creator & Lead Maintainer
|
|
||||||
</td>
|
|
||||||
<td align="center">
|
|
||||||
<a href="https://github.com/Lluciocc">
|
|
||||||
<img src="https://github.com/Lluciocc.png?size=80" width="60" /><br />
|
|
||||||
<sub><b>Lluciocc</b></sub>
|
|
||||||
</a><br />
|
|
||||||
Maintainer
|
|
||||||
</td>
|
|
||||||
<td align="center">
|
|
||||||
<a href="https://github.com/Mellurboo">
|
|
||||||
<img src="https://github.com/Mellurboo.png?size=80" width="60" /><br />
|
|
||||||
<sub><b>Mellurboo</b></sub>
|
|
||||||
</a><br />
|
|
||||||
Contributor
|
|
||||||
</td>
|
|
||||||
<td align="center">
|
|
||||||
<a href="https://github.com/Artemix1508">
|
|
||||||
<img src="https://github.com/Artemix1508.png?size=80" width="60" /><br />
|
|
||||||
<sub><b>Artemix1508</b></sub>
|
|
||||||
</a><br />
|
|
||||||
Artwork
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center">
|
|
||||||
<a href="https://github.com/zeyadhost">
|
|
||||||
<img src="https://github.com/zeyadhost.png?size=80" width="60" /><br />
|
|
||||||
<sub><b>Zeyadhost</b></sub>
|
|
||||||
</a><br />
|
|
||||||
Contributor
|
|
||||||
</td>
|
|
||||||
<td align="center">
|
|
||||||
<a href="https://github.com/naplon74">
|
|
||||||
<img src="https://github.com/naplon74.png?size=80" width="60" /><br />
|
|
||||||
<sub><b>Naplon74</b></sub>
|
|
||||||
</a><br />
|
|
||||||
Artwork
|
|
||||||
</td>
|
|
||||||
<td align="center">
|
|
||||||
<a href="https://github.com/pixelyblah">
|
|
||||||
<img src="https://github.com/pixelyblah.png?size=80" width="60" /><br />
|
|
||||||
<sub><b>pixelyblah</b></sub>
|
|
||||||
</a><br />
|
|
||||||
Artwork
|
|
||||||
</td>
|
|
||||||
<td align="center">
|
|
||||||
<a href="https://github.com/qwroffc">
|
|
||||||
<img src="https://github.com/qwroffc.png?size=80" width="60" /><br />
|
|
||||||
<sub><b>qwroffc</b></sub>
|
|
||||||
</a><br />
|
|
||||||
Artwork
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ☕ Support the Journey
|
|
||||||
|
|
||||||
If you find BoredOS interesting or useful, consider fueling development with a coffee!
|
|
||||||
|
|
||||||
<a href="https://buymeacoffee.com/boreddevhq" target="_blank">
|
|
||||||
<img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="50" style="border-radius: 8px;" />
|
|
||||||
</a>
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## History
|
|
||||||
|
|
||||||
**BoredOS** is the successor to **[BrewKernel](https://github.com/boreddevnl/brewkernel)**, a project started in 2023. BrewKernel served as the foundational learning ground but has since been officially deprecated and archived — it no longer receives updates, bug fixes, or pull request reviews.
|
|
||||||
|
|
||||||
BoredOS is a complete architectural reboot, applying years of lessons learned to build a cleaner, more modular, and more capable system.
|
|
||||||
|
|
||||||
> [!IMPORTANT]
|
|
||||||
> Please direct all issues, discussions, and contributions to this repository. Legacy BrewKernel code is preserved for historical purposes only and is not compatible with BoredOS.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
**Copyright (C) 2023–2026 boreddevnl**
|
|
||||||
|
|
||||||
Distributed under the **GNU General Public License v3**. See [`LICENSE`](LICENSE) for details.
|
|
||||||
|
|
||||||
> [!IMPORTANT]
|
|
||||||
> You must retain all copyright headers and include the original attribution in any redistributions or derivative works. See the [`NOTICE`](NOTICE) file for more details.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ☕ Support the Journey
|
## ☕ Support the Journey
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,88 @@ The BoredOS Terminal provides a powerful command-line interface (CLI) for advanc
|
||||||
The default shell in BoredOS is **BoredShell (Bsh)**, a userspace shell with a dedicated terminal app. It features:
|
The default shell in BoredOS is **BoredShell (Bsh)**, a userspace shell with a dedicated terminal app. It features:
|
||||||
- **ANSI Color Support**: Rich text output with colors and styles.
|
- **ANSI Color Support**: Rich text output with colors and styles.
|
||||||
- **Command History**: Use the **Up** and **Down** arrow keys to navigate through your previous commands (up to 64 history entries).
|
- **Command History**: Use the **Up** and **Down** arrow keys to navigate through your previous commands (up to 64 history entries).
|
||||||
- **Output Redirection**:
|
- **Redirection**:
|
||||||
- `command > file`: Write output to a new file (or overwrite existing).
|
- `command > file`: Write output to a new file (or overwrite existing).
|
||||||
- `command >> file`: Append output to an existing file.
|
- `command >> file`: Append output to an existing file.
|
||||||
|
- `command < file`: Use a file as command input.
|
||||||
- **Piping**:
|
- **Piping**:
|
||||||
- `command1 | command2`: Pass the output of the first command as input to the second.
|
- `command1 | command2`: Pass the output of the first command as input to the second.
|
||||||
|
- **Command Chaining**:
|
||||||
|
- `cmd1 ; cmd2`: Run `cmd2` after `cmd1`.
|
||||||
|
- `cmd1 && cmd2`: Run `cmd2` only if `cmd1` succeeds.
|
||||||
|
- `cmd1 || cmd2`: Run `cmd2` only if `cmd1` fails.
|
||||||
|
- **Background Launch**:
|
||||||
|
- `command &`: Start command without blocking the prompt.
|
||||||
|
|
||||||
|
## Shell Operators & Scripting
|
||||||
|
|
||||||
|
Bsh provides a suite of operators for managing I/O and controlling execution flow.
|
||||||
|
|
||||||
|
### I/O Redirection
|
||||||
|
|
||||||
|
Redirection allows you to change where a command reads its input from or writes its output to by manipulating kernel-level file descriptors (FDs).
|
||||||
|
|
||||||
|
| Operator | Action | Description |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| `>` | **Overwrite** | Redirects standard output (FD 1) to a file, creating it if it doesn't exist or truncating it if it does. |
|
||||||
|
| `>>` | **Append** | Redirects standard output (FD 1) to a file, appending new data to the end without clearing existing content. |
|
||||||
|
| `<` | **Input** | Redirects standard input (FD 0) to read from a file instead of the terminal. |
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```bash
|
||||||
|
echo "Hello World" > greetings.txt
|
||||||
|
echo "Second line" >> greetings.txt
|
||||||
|
cat < greetings.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
**How it works:**
|
||||||
|
The shell uses `sys_open` to obtain a handle for the target file, then uses `sys_dup2` to replace the process's standard FD (0 or 1) with the new file handle. This ensures the command's standard library calls (like `printf` or `scanf`) interact with the file instead of the terminal.
|
||||||
|
|
||||||
|
### Pipelines (`|`)
|
||||||
|
|
||||||
|
Pipelines connect the output of one command directly to the input of another.
|
||||||
|
|
||||||
|
**Usage:** `cmd1 | cmd2 | cmd3`
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```bash
|
||||||
|
ls /bin | cat | cat
|
||||||
|
```
|
||||||
|
|
||||||
|
**How it works:**
|
||||||
|
The shell creates an anonymous pipe using `sys_pipe`, which returns two FDs: a read end and a write end.
|
||||||
|
- The shell duplicates the **write end** to FD 1 for the first command.
|
||||||
|
- The shell duplicates the **read end** to FD 0 for the second command.
|
||||||
|
- Both commands run in parallel, and the kernel manages the data buffer between them.
|
||||||
|
|
||||||
|
### Execution Control
|
||||||
|
|
||||||
|
| Operator | Name | Description |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| `;` | **Semicolon** | Executes commands sequentially. `cmd2` runs only after `cmd1` finishes. |
|
||||||
|
| `&&` | **Logical AND** | Executes `cmd2` only if `cmd1` returns a success status (exit code 0). |
|
||||||
|
| `||` | **Logical OR** | Executes `cmd2` only if `cmd1` fails (returns a non-zero exit code). |
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```bash
|
||||||
|
# Compile and run only on success
|
||||||
|
make && ./boredos.elf
|
||||||
|
|
||||||
|
# Recover from a missing command
|
||||||
|
missing_tool || echo "Tool not found, using fallback"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Background Execution (`&`)
|
||||||
|
|
||||||
|
Appending `&` to a command tells the shell not to wait for the process to complete before returning to the prompt.
|
||||||
|
|
||||||
|
**How it works:**
|
||||||
|
Normally, the shell calls `sys_waitpid` to block until a child process exits. With `&`, the shell skips this wait, allowing the process to run asynchronously while you continue using the terminal.
|
||||||
|
|
||||||
|
Operator precedence follows common POSIX shell rules:
|
||||||
|
1. Redirection and pipelines (`<`, `>`, `>>`, `|`)
|
||||||
|
2. Conditionals (`&&`, `||`)
|
||||||
|
3. List separators (`;`, `&`)
|
||||||
|
|
||||||
### Bsh Configuration
|
### Bsh Configuration
|
||||||
|
|
||||||
|
|
@ -49,13 +126,13 @@ Below are some of the most used commands available in `/bin`:
|
||||||
| `ls` | List files and directories in the current path. |
|
| `ls` | List files and directories in the current path. |
|
||||||
| `cd` | Change the current working directory. |
|
| `cd` | Change the current working directory. |
|
||||||
| `cat` | Display the contents of a file. |
|
| `cat` | Display the contents of a file. |
|
||||||
| `ls` | List directory contents. |
|
|
||||||
| `rm` | Remove a file. |
|
| `rm` | Remove a file. |
|
||||||
| `mkdir` | Create a new directory. |
|
| `mkdir` | Create a new directory. |
|
||||||
| `man` | View the manual for a specific command (e.g., `man ls`). |
|
| `man` | View the manual for a specific command (e.g., `man ls`). |
|
||||||
| `lsblk` | List block devices and partitions with size, type, filesystem, label, and flags. |
|
| `lsblk` | List block devices and partitions. |
|
||||||
| `du` | Report disk usage for files and directories, recursively. |
|
| `du` | Report disk usage for files and directories. |
|
||||||
| `sysfetch` | Display system and hardware information. |
|
| `sysfetch` | Display system information and BoredOS branding. |
|
||||||
|
| `time` | Measure command execution time. |
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
||||||
BIN
src/images/wallpapers/Drift.png
Normal file
BIN
src/images/wallpapers/Drift.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 830 KiB |
|
|
@ -302,6 +302,40 @@ process_t* process_create_elf(const char* filepath, const char* args_str, bool t
|
||||||
new_proc->fd_kind[i] = 0;
|
new_proc->fd_kind[i] = 0;
|
||||||
new_proc->fd_flags[i] = 0;
|
new_proc->fd_flags[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
process_t *parent = process_get_current();
|
||||||
|
if (parent) {
|
||||||
|
for (int i = 0; i < MAX_PROCESS_FDS; i++) {
|
||||||
|
if (parent->fds[i]) {
|
||||||
|
new_proc->fds[i] = parent->fds[i];
|
||||||
|
new_proc->fd_kind[i] = parent->fd_kind[i];
|
||||||
|
new_proc->fd_flags[i] = parent->fd_flags[i];
|
||||||
|
|
||||||
|
if (new_proc->fd_kind[i] == PROC_FD_KIND_FILE) {
|
||||||
|
process_fd_file_ref_t *ref = (process_fd_file_ref_t *)new_proc->fds[i];
|
||||||
|
if (ref) ref->refs++;
|
||||||
|
} else if (new_proc->fd_kind[i] == PROC_FD_KIND_PIPE_READ) {
|
||||||
|
process_fd_pipe_t *pipe = (process_fd_pipe_t *)new_proc->fds[i];
|
||||||
|
if (pipe) pipe->readers++;
|
||||||
|
} else if (new_proc->fd_kind[i] == PROC_FD_KIND_PIPE_WRITE) {
|
||||||
|
process_fd_pipe_t *pipe = (process_fd_pipe_t *)new_proc->fds[i];
|
||||||
|
if (pipe) pipe->writers++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always set up TTY FDs if a TTY is provided and they aren't already set
|
||||||
|
if (tty_id >= 0) {
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
if (!new_proc->fds[i]) {
|
||||||
|
new_proc->fds[i] = (void*)(uint64_t)1;
|
||||||
|
new_proc->fd_kind[i] = PROC_FD_KIND_TTY;
|
||||||
|
new_proc->fd_flags[i] = (i == 0) ? 0 : 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
new_proc->gui_event_head = 0;
|
new_proc->gui_event_head = 0;
|
||||||
new_proc->gui_event_tail = 0;
|
new_proc->gui_event_tail = 0;
|
||||||
new_proc->ui_window = NULL;
|
new_proc->ui_window = NULL;
|
||||||
|
|
@ -314,7 +348,6 @@ process_t* process_create_elf(const char* filepath, const char* args_str, bool t
|
||||||
new_proc->exit_status = 0;
|
new_proc->exit_status = 0;
|
||||||
process_init_signal_state(new_proc);
|
process_init_signal_state(new_proc);
|
||||||
|
|
||||||
process_t *parent = process_get_current();
|
|
||||||
if (parent) {
|
if (parent) {
|
||||||
extern void mem_memcpy(void *dest, const void *src, size_t len);
|
extern void mem_memcpy(void *dest, const void *src, size_t len);
|
||||||
mem_memcpy(new_proc->cwd, parent->cwd, 1024);
|
mem_memcpy(new_proc->cwd, parent->cwd, 1024);
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
#define PROC_FD_KIND_FILE 1
|
#define PROC_FD_KIND_FILE 1
|
||||||
#define PROC_FD_KIND_PIPE_READ 2
|
#define PROC_FD_KIND_PIPE_READ 2
|
||||||
#define PROC_FD_KIND_PIPE_WRITE 3
|
#define PROC_FD_KIND_PIPE_WRITE 3
|
||||||
|
#define PROC_FD_KIND_TTY 4
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
void *file;
|
void *file;
|
||||||
|
|
|
||||||
|
|
@ -1102,6 +1102,12 @@ static uint64_t fs_cmd_read(const syscall_args_t *args) {
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (proc->fd_kind[fd] == PROC_FD_KIND_TTY) {
|
||||||
|
if (proc->tty_id < 0) return (uint64_t)-1;
|
||||||
|
extern int tty_read_input(int tty_id, char *buf, size_t len);
|
||||||
|
return (uint64_t)tty_read_input(proc->tty_id, (char *)buf, (size_t)len);
|
||||||
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1139,6 +1145,12 @@ static uint64_t fs_cmd_write(const syscall_args_t *args) {
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (proc->fd_kind[fd] == PROC_FD_KIND_TTY) {
|
||||||
|
if (proc->tty_id < 0) return (uint64_t)-1;
|
||||||
|
extern int tty_write_output(int tty_id, const char *buf, size_t len);
|
||||||
|
return (uint64_t)tty_write_output(proc->tty_id, (const char *)buf, (size_t)len);
|
||||||
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
93
src/userland/cli/find.c
Normal file
93
src/userland/cli/find.c
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "syscall.h"
|
||||||
|
|
||||||
|
int type = 0; // 0 is nothing, 1 is file, 2 is dir
|
||||||
|
char *name = NULL;
|
||||||
|
char *dir = "."; // random char bc it needs to have anything in it
|
||||||
|
|
||||||
|
// match exact name
|
||||||
|
int match(const char *a, const char *b) {
|
||||||
|
return strcmp(a, b) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if its a file with fopen
|
||||||
|
int isfile(const char *path) {
|
||||||
|
FILE *fp = fopen(path, "r");
|
||||||
|
if (fp) {
|
||||||
|
fclose(fp);
|
||||||
|
return 1; }
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// recursive find
|
||||||
|
void find(const char *path) {
|
||||||
|
FAT32_FileInfo ents[128];
|
||||||
|
int n = sys_list(path, ents, 128);
|
||||||
|
if (n < 0) return;
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
const char *filename = ents[i].name;
|
||||||
|
if (match(filename, ".") || match(filename, "..")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
char full[512];
|
||||||
|
strcpy(full, path);
|
||||||
|
strcat(full, "/");
|
||||||
|
strcat(full, filename);
|
||||||
|
|
||||||
|
int f = isfile(full);
|
||||||
|
if (match(filename, name)) {
|
||||||
|
if (type == 0 || (type == 1 && f) || (type == 2 && !f)) {
|
||||||
|
printf("%s\n", full);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!f) {
|
||||||
|
find(full);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
// check if user needs help
|
||||||
|
if (argc > 1 && strcmp(argv[1], "--help") == 0) {
|
||||||
|
printf("Usage: find [DIR] [-name] [pattern] [-type] [d/f]\n");
|
||||||
|
printf("Options:\n");
|
||||||
|
printf("-type d: only read dir\n");
|
||||||
|
printf("-type f: only read files\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// check for flags
|
||||||
|
for (int i = 1; i < argc; i++) {
|
||||||
|
if (argv[i][0] == '-') {
|
||||||
|
if (match(argv[i], "-name") && i+1 < argc) {
|
||||||
|
name = argv[++i];
|
||||||
|
}
|
||||||
|
else if (match(argv[i], "-type") && i+1 < argc) {
|
||||||
|
i++;
|
||||||
|
if (match(argv[i], "f")) {
|
||||||
|
type = 1;
|
||||||
|
}
|
||||||
|
else if (match(argv[i], "d")) {
|
||||||
|
type = 2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("-only type f or d\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if dir hasnt been set yet
|
||||||
|
else if (dir[0] == '.') {
|
||||||
|
dir = argv[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!name) {
|
||||||
|
printf("Wrong usage, --help for more info\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
find(dir);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
262
src/userland/cli/grep.c
Normal file
262
src/userland/cli/grep.c
Normal file
|
|
@ -0,0 +1,262 @@
|
||||||
|
// Copyright (c) 2026 maro (whitehai11)
|
||||||
|
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
|
||||||
|
// This header needs to maintain in any file it is present in, as per the GPL license terms.
|
||||||
|
// BOREDOS_APP_DESC: Search for text inside a file.
|
||||||
|
|
||||||
|
#include "../libc/syscall.h"
|
||||||
|
#include "../libc/stdlib.h"
|
||||||
|
#include "../libc/string.h"
|
||||||
|
#include "../libc/stdio.h"
|
||||||
|
|
||||||
|
#define READ_BUF_SIZE 4096
|
||||||
|
#define LINE_BUF_SIZE 1024
|
||||||
|
#define MAX_PATH 512
|
||||||
|
#define MAX_ENTRIES 256
|
||||||
|
|
||||||
|
// Flags
|
||||||
|
static int g_show_numbers = 0;
|
||||||
|
static int g_ignore_case = 0;
|
||||||
|
static int g_count_only = 0;
|
||||||
|
static int g_invert = 0; // -v
|
||||||
|
static int g_files_only = 0; // -l
|
||||||
|
static int g_word_match = 0; // -w
|
||||||
|
static int g_line_match = 0; // -x
|
||||||
|
static int g_recursive = 0; // -r / -R
|
||||||
|
static int g_multi_file = 0; // more than one file → prefix output with filename
|
||||||
|
|
||||||
|
static const char *g_pattern = NULL;
|
||||||
|
|
||||||
|
// Total match count across all files (used for -c with -r)
|
||||||
|
static int g_total_matches = 0;
|
||||||
|
|
||||||
|
static int sc_strcmp(const char *a, const char *b) {
|
||||||
|
while (*a && *a == *b) { a++; b++; }
|
||||||
|
return (unsigned char)*a - (unsigned char)*b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_usage(void) {
|
||||||
|
printf("Usage: grep [options] <pattern> <file> [file...]\n");
|
||||||
|
printf("\n");
|
||||||
|
printf("Search for text inside files.\n");
|
||||||
|
printf("\n");
|
||||||
|
printf("Options:\n");
|
||||||
|
printf(" -n Show line numbers\n");
|
||||||
|
printf(" -i Case-insensitive search\n");
|
||||||
|
printf(" -c Print match count only\n");
|
||||||
|
printf(" -v Invert match (print non-matching lines)\n");
|
||||||
|
printf(" -l Print only filenames with matches\n");
|
||||||
|
printf(" -w Match whole words only\n");
|
||||||
|
printf(" -x Match whole lines only\n");
|
||||||
|
printf(" -r, -R Recursive search in directories\n");
|
||||||
|
printf(" -h Show this help\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static char to_lower(char c) {
|
||||||
|
if (c >= 'A' && c <= 'Z') return c + 32;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int is_word_char(char c) {
|
||||||
|
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
|
||||||
|
(c >= '0' && c <= '9') || c == '_';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if needle appears in haystack at position i as a whole word */
|
||||||
|
static int match_at(const char *haystack, int i, int h_len,
|
||||||
|
const char *needle, int n_len, int ignore_case) {
|
||||||
|
for (int j = 0; j < n_len; j++) {
|
||||||
|
char h = ignore_case ? to_lower(haystack[i + j]) : haystack[i + j];
|
||||||
|
char n = ignore_case ? to_lower(needle[j]) : needle[j];
|
||||||
|
if (h != n) return 0;
|
||||||
|
}
|
||||||
|
if (g_word_match) {
|
||||||
|
if (i > 0 && is_word_char(haystack[i - 1])) return 0;
|
||||||
|
if (i + n_len < h_len && is_word_char(haystack[i + n_len])) return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int str_contains(const char *haystack, const char *needle, int ignore_case) {
|
||||||
|
int h_len = (int)strlen(haystack);
|
||||||
|
int n_len = (int)strlen(needle);
|
||||||
|
|
||||||
|
if (n_len == 0) return 1;
|
||||||
|
if (n_len > h_len) return 0;
|
||||||
|
|
||||||
|
for (int i = 0; i <= h_len - n_len; i++) {
|
||||||
|
if (match_at(haystack, i, h_len, needle, n_len, ignore_case))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int line_matches(const char *line) {
|
||||||
|
if (g_line_match) {
|
||||||
|
/* Whole line must equal pattern */
|
||||||
|
int h_len = (int)strlen(line);
|
||||||
|
int n_len = (int)strlen(g_pattern);
|
||||||
|
if (h_len != n_len) return 0;
|
||||||
|
return match_at(line, 0, h_len, g_pattern, n_len, g_ignore_case);
|
||||||
|
}
|
||||||
|
return str_contains(line, g_pattern, g_ignore_case);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grep a single open file descriptor, printing results prefixed by filename if needed */
|
||||||
|
static int grep_fd(int fd, const char *filename) {
|
||||||
|
static char read_buf[READ_BUF_SIZE];
|
||||||
|
static char line[LINE_BUF_SIZE];
|
||||||
|
int line_pos = 0;
|
||||||
|
int line_num = 0;
|
||||||
|
int match_cnt = 0;
|
||||||
|
|
||||||
|
/* Helper: process one complete line */
|
||||||
|
#define PROCESS_LINE() do { \
|
||||||
|
line[line_pos] = '\0'; \
|
||||||
|
line_num++; \
|
||||||
|
int matched = line_matches(line); \
|
||||||
|
if (g_invert) matched = !matched; \
|
||||||
|
if (matched) { \
|
||||||
|
match_cnt++; \
|
||||||
|
if (!g_count_only && !g_files_only) { \
|
||||||
|
if (g_multi_file) printf("%s:", filename); \
|
||||||
|
if (g_show_numbers) printf("%d:", line_num); \
|
||||||
|
printf("%s\n", line); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
line_pos = 0; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
int bytes = sys_read(fd, read_buf, READ_BUF_SIZE);
|
||||||
|
if (bytes <= 0) break;
|
||||||
|
|
||||||
|
for (int i = 0; i < bytes; i++) {
|
||||||
|
char c = read_buf[i];
|
||||||
|
if (c == '\n' || line_pos >= LINE_BUF_SIZE - 1) {
|
||||||
|
PROCESS_LINE();
|
||||||
|
} else if (c != '\r') {
|
||||||
|
line[line_pos++] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (line_pos > 0) PROCESS_LINE();
|
||||||
|
|
||||||
|
#undef PROCESS_LINE
|
||||||
|
|
||||||
|
if (g_count_only)
|
||||||
|
printf("%s%d\n", g_multi_file ? filename : "", match_cnt > 0 ? match_cnt : 0);
|
||||||
|
|
||||||
|
if (g_files_only && match_cnt > 0)
|
||||||
|
printf("%s\n", filename);
|
||||||
|
|
||||||
|
g_total_matches += match_cnt;
|
||||||
|
return match_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int grep_file(const char *path) {
|
||||||
|
int fd = sys_open(path, "r");
|
||||||
|
if (fd < 0) {
|
||||||
|
printf("grep: cannot open '%s'\n", path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int n = grep_fd(fd, path);
|
||||||
|
sys_close(fd);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void grep_recursive(const char *path) {
|
||||||
|
FAT32_FileInfo info;
|
||||||
|
if (sys_get_file_info(path, &info) < 0) {
|
||||||
|
printf("grep: cannot access '%s'\n", path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info.is_directory) {
|
||||||
|
grep_file(path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FAT32_FileInfo entries[MAX_ENTRIES];
|
||||||
|
int count = sys_list(path, entries, MAX_ENTRIES);
|
||||||
|
if (count < 0) return;
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
const char *name = entries[i].name;
|
||||||
|
if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
char full[MAX_PATH];
|
||||||
|
int plen = (int)strlen(path);
|
||||||
|
int nlen = (int)strlen(name);
|
||||||
|
if (plen + 1 + nlen + 1 > MAX_PATH) continue;
|
||||||
|
|
||||||
|
int slash = (plen == 1 && path[0] == '/') ? 0 : 1;
|
||||||
|
for (int j = 0; j < plen; j++) full[j] = path[j];
|
||||||
|
if (slash) full[plen] = '/';
|
||||||
|
for (int j = 0; j <= nlen; j++) full[plen + slash + j] = name[j];
|
||||||
|
|
||||||
|
if (entries[i].is_directory)
|
||||||
|
grep_recursive(full);
|
||||||
|
else
|
||||||
|
grep_file(full);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
int arg_offset = 1;
|
||||||
|
|
||||||
|
for (int i = 1; i < argc; i++) {
|
||||||
|
if (argv[i][0] != '-') break;
|
||||||
|
if (sc_strcmp(argv[i], "-n") == 0) {
|
||||||
|
g_show_numbers = 1; arg_offset++;
|
||||||
|
} else if (sc_strcmp(argv[i], "-i") == 0) {
|
||||||
|
g_ignore_case = 1; arg_offset++;
|
||||||
|
} else if (sc_strcmp(argv[i], "-c") == 0) {
|
||||||
|
g_count_only = 1; arg_offset++;
|
||||||
|
} else if (sc_strcmp(argv[i], "-v") == 0) {
|
||||||
|
g_invert = 1; arg_offset++;
|
||||||
|
} else if (sc_strcmp(argv[i], "-l") == 0) {
|
||||||
|
g_files_only = 1; arg_offset++;
|
||||||
|
} else if (sc_strcmp(argv[i], "-w") == 0) {
|
||||||
|
g_word_match = 1; arg_offset++;
|
||||||
|
} else if (sc_strcmp(argv[i], "-x") == 0) {
|
||||||
|
g_line_match = 1; arg_offset++;
|
||||||
|
} else if (sc_strcmp(argv[i], "-r") == 0 ||
|
||||||
|
sc_strcmp(argv[i], "-R") == 0) {
|
||||||
|
g_recursive = 1; arg_offset++;
|
||||||
|
} else if (sc_strcmp(argv[i], "-h") == 0 ||
|
||||||
|
sc_strcmp(argv[i], "--help") == 0) {
|
||||||
|
print_usage();
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
printf("grep: unknown option '%s'\n", argv[i]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc - arg_offset < 1) {
|
||||||
|
print_usage();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_pattern = argv[arg_offset];
|
||||||
|
|
||||||
|
// Need at least a path when not reading stdin
|
||||||
|
if (argc - arg_offset < 2) {
|
||||||
|
print_usage();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiple files → prefix output with filename
|
||||||
|
g_multi_file = (argc - arg_offset > 2) || g_recursive;
|
||||||
|
|
||||||
|
for (int i = arg_offset + 1; i < argc; i++) {
|
||||||
|
if (g_recursive) {
|
||||||
|
grep_recursive(argv[i]);
|
||||||
|
} else {
|
||||||
|
grep_file(argv[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_total_matches > 0 ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
@ -323,13 +323,22 @@ int main(int argc, char **argv) {
|
||||||
int b = sys_read(fd_u, u_buf, 63);
|
int b = sys_read(fd_u, u_buf, 63);
|
||||||
u_buf[b] = 0;
|
u_buf[b] = 0;
|
||||||
sys_close(fd_u);
|
sys_close(fd_u);
|
||||||
int sec = atoi(u_buf);
|
int sec = atoi(u_buf);
|
||||||
int mins = sec / 60;
|
int days = sec / 86400;
|
||||||
|
int hrs = (sec % 86400) / 3600;
|
||||||
|
int mins = (sec % 3600) / 60;
|
||||||
strcpy(info_lines[info_line_count], config.uptime_label);
|
strcpy(info_lines[info_line_count], config.uptime_label);
|
||||||
strcat(info_lines[info_line_count], ": ");
|
strcat(info_lines[info_line_count], ": ");
|
||||||
itoa(mins, temp_buf);
|
if (days > 0) {
|
||||||
strcat(info_lines[info_line_count], temp_buf);
|
itoa(days, temp_buf); strcat(info_lines[info_line_count], temp_buf);
|
||||||
strcat(info_lines[info_line_count++], " mins");
|
strcat(info_lines[info_line_count], days == 1 ? " day, " : " days, ");
|
||||||
|
}
|
||||||
|
if (hrs > 0 || days > 0) {
|
||||||
|
itoa(hrs, temp_buf); strcat(info_lines[info_line_count], temp_buf);
|
||||||
|
strcat(info_lines[info_line_count], hrs == 1 ? " hour, " : " hours, ");
|
||||||
|
}
|
||||||
|
itoa(mins, temp_buf); strcat(info_lines[info_line_count], temp_buf);
|
||||||
|
strcat(info_lines[info_line_count++], mins == 1 ? " min" : " mins");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (config.cpu_label[0]) {
|
if (config.cpu_label[0]) {
|
||||||
|
|
|
||||||
|
|
@ -1,144 +0,0 @@
|
||||||
// Copyright (c) 2026 Lluciocc (https://github.com/lluciocc)
|
|
||||||
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
|
|
||||||
// This header needs to maintain in any file it is present in, as per the GPL license terms.
|
|
||||||
|
|
||||||
#include "stdlib.h"
|
|
||||||
#include "syscall.h"
|
|
||||||
|
|
||||||
// CMDLINE_MAX includes the trailing NUL, so at most 511 command-line bytes can
|
|
||||||
// be reconstructed here. Unchecked concatenation can overflow CMDLINE_MAX; all
|
|
||||||
// command-line construction in this file must go through the checked append
|
|
||||||
// helpers below.
|
|
||||||
#define CMDLINE_MAX 512
|
|
||||||
|
|
||||||
static int has_slash(const char *s) {
|
|
||||||
while (s && *s) {
|
|
||||||
if (*s == '/')
|
|
||||||
return 1;
|
|
||||||
s++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ends_with_elf(const char *s) {
|
|
||||||
int len;
|
|
||||||
|
|
||||||
if (!s)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
len = strlen(s);
|
|
||||||
|
|
||||||
if (len < 4)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return strcmp(s + len - 4, ".elf") == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_usage(void) {
|
|
||||||
printf("Usage: time <command> [args...]\n");
|
|
||||||
printf("\n");
|
|
||||||
printf("Examples:\n");
|
|
||||||
printf(" time ls\n");
|
|
||||||
printf(" time hexdump file.txt\n");
|
|
||||||
printf(" time /bin/hexdump.elf file.txt\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the system uptime in milliseconds by reading /proc/uptime and parsing the first number (seconds).
|
|
||||||
static unsigned long long read_uptime_ms(void) {
|
|
||||||
char buf[64];
|
|
||||||
int fd;
|
|
||||||
int bytes;
|
|
||||||
int seconds;
|
|
||||||
|
|
||||||
fd = sys_open("/proc/uptime", "r");
|
|
||||||
|
|
||||||
if (fd < 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
bytes = sys_read(fd, buf, sizeof(buf) - 1);
|
|
||||||
|
|
||||||
sys_close(fd);
|
|
||||||
|
|
||||||
if (bytes <= 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
buf[bytes] = 0;
|
|
||||||
|
|
||||||
seconds = atoi(buf);
|
|
||||||
|
|
||||||
return (unsigned long long)seconds * 1000ULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the command line for execution
|
|
||||||
// If the first argument contains a slash, use it as is. Otherwise, prepend "/bin/" and append ".elf" if it doesn't already end with ".elf".
|
|
||||||
static void build_command_line(int argc, char **argv, char *out) {
|
|
||||||
int i;
|
|
||||||
|
|
||||||
out[0] = 0;
|
|
||||||
|
|
||||||
if (has_slash(argv[1])) {
|
|
||||||
strcat(out, argv[1]);
|
|
||||||
} else {
|
|
||||||
strcat(out, "/bin/");
|
|
||||||
strcat(out, argv[1]);
|
|
||||||
|
|
||||||
if (!ends_with_elf(argv[1])) {
|
|
||||||
strcat(out, ".elf");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 2; i < argc; i++) {
|
|
||||||
strcat(out, " ");
|
|
||||||
strcat(out, argv[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
char cmdline[CMDLINE_MAX];
|
|
||||||
|
|
||||||
unsigned long long start;
|
|
||||||
unsigned long long end;
|
|
||||||
unsigned long long elapsed;
|
|
||||||
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (argc < 2) {
|
|
||||||
print_usage();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(argv[1], "-h") == 0 ||
|
|
||||||
strcmp(argv[1], "--help") == 0) {
|
|
||||||
print_usage();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
build_command_line(argc, argv, cmdline);
|
|
||||||
|
|
||||||
start = read_uptime_ms();
|
|
||||||
|
|
||||||
ret = system(cmdline);
|
|
||||||
|
|
||||||
end = read_uptime_ms();
|
|
||||||
|
|
||||||
if (end >= start)
|
|
||||||
elapsed = end - start;
|
|
||||||
else
|
|
||||||
elapsed = 0;
|
|
||||||
|
|
||||||
printf("\n");
|
|
||||||
printf("Command: %s\n", cmdline);
|
|
||||||
printf("Exit code: %d\n", ret);
|
|
||||||
|
|
||||||
if (ret == -1) {
|
|
||||||
printf("Command failed with non-zero exit code, not reporting time.\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Elapsed: %llu ms\n", elapsed);
|
|
||||||
|
|
||||||
sys_system(SYSTEM_CMD_SLEEP, 1, 0, 0, 0);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
@ -1235,10 +1235,22 @@ int main(void) {
|
||||||
for (int i = 0; i < g_tab_count; i++) {
|
for (int i = 0; i < g_tab_count; i++) {
|
||||||
TerminalSession *s = &g_tabs[i];
|
TerminalSession *s = &g_tabs[i];
|
||||||
int read = 0;
|
int read = 0;
|
||||||
|
|
||||||
|
// Read any remaining output from the TTY
|
||||||
while ((read = sys_tty_read_out(s->tty_id, out_buf, sizeof(out_buf))) > 0) {
|
while ((read = sys_tty_read_out(s->tty_id, out_buf, sizeof(out_buf))) > 0) {
|
||||||
session_process_output(s, out_buf, read);
|
session_process_output(s, out_buf, read);
|
||||||
if (i == g_active_tab) dirty = true;
|
if (i == g_active_tab) dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if the shell process has exited
|
||||||
|
if it has, close the tab.*/
|
||||||
|
int status = 0;
|
||||||
|
if (sys_waitpid(s->bsh_pid, &status, 1) > 0) {
|
||||||
|
close_tab(i);
|
||||||
|
i--;
|
||||||
|
dirty = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (ui_get_event(g_win, &ev)) {
|
while (ui_get_event(g_win, &ev)) {
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ typedef struct {
|
||||||
int refcount;
|
int refcount;
|
||||||
int flags;
|
int flags;
|
||||||
int kernel_fd;
|
int kernel_fd;
|
||||||
|
int owns_kernel_fd;
|
||||||
pipe_state_t *pipe;
|
pipe_state_t *pipe;
|
||||||
} fd_handle_t;
|
} fd_handle_t;
|
||||||
|
|
||||||
|
|
@ -60,6 +61,10 @@ static fd_handle_t *g_fd_table[POSIX_MAX_FDS];
|
||||||
static fd_handle_t g_stdio_handles[3];
|
static fd_handle_t g_stdio_handles[3];
|
||||||
static int g_fd_initialized = 0;
|
static int g_fd_initialized = 0;
|
||||||
|
|
||||||
|
static int _b_is_stdio_handle(const fd_handle_t *h) {
|
||||||
|
return (h >= &g_stdio_handles[0] && h <= &g_stdio_handles[2]);
|
||||||
|
}
|
||||||
|
|
||||||
static void _b_fd_init(void) {
|
static void _b_fd_init(void) {
|
||||||
int i;
|
int i;
|
||||||
if (g_fd_initialized) {
|
if (g_fd_initialized) {
|
||||||
|
|
@ -73,6 +78,7 @@ static void _b_fd_init(void) {
|
||||||
g_stdio_handles[i].refcount = 1;
|
g_stdio_handles[i].refcount = 1;
|
||||||
g_stdio_handles[i].flags = O_RDWR;
|
g_stdio_handles[i].flags = O_RDWR;
|
||||||
g_stdio_handles[i].kernel_fd = i;
|
g_stdio_handles[i].kernel_fd = i;
|
||||||
|
g_stdio_handles[i].owns_kernel_fd = 0;
|
||||||
g_stdio_handles[i].pipe = NULL;
|
g_stdio_handles[i].pipe = NULL;
|
||||||
g_fd_table[i] = &g_stdio_handles[i];
|
g_fd_table[i] = &g_stdio_handles[i];
|
||||||
}
|
}
|
||||||
|
|
@ -274,6 +280,7 @@ __attribute__((weak)) int open(const char *pathname, int flags, ...) {
|
||||||
h->refcount = 1;
|
h->refcount = 1;
|
||||||
h->flags = flags;
|
h->flags = flags;
|
||||||
h->kernel_fd = kfd;
|
h->kernel_fd = kfd;
|
||||||
|
h->owns_kernel_fd = 1;
|
||||||
h->pipe = NULL;
|
h->pipe = NULL;
|
||||||
g_fd_table[fd] = h;
|
g_fd_table[fd] = h;
|
||||||
|
|
||||||
|
|
@ -300,7 +307,7 @@ __attribute__((weak)) int close(int fd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (h->type == HANDLE_KERNEL_FD) {
|
if (h->type == HANDLE_KERNEL_FD) {
|
||||||
if (h->kernel_fd >= 3) {
|
if (h->owns_kernel_fd) {
|
||||||
sys_close(h->kernel_fd);
|
sys_close(h->kernel_fd);
|
||||||
}
|
}
|
||||||
} else if (h->type == HANDLE_PIPE_READ || h->type == HANDLE_PIPE_WRITE) {
|
} else if (h->type == HANDLE_PIPE_READ || h->type == HANDLE_PIPE_WRITE) {
|
||||||
|
|
@ -384,10 +391,13 @@ __attribute__((weak)) ssize_t write(int fd, const void *buf, size_t count) {
|
||||||
return (ssize_t)n;
|
return (ssize_t)n;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (h->kernel_fd <= 2) {
|
if (_b_is_stdio_handle(h)) {
|
||||||
n = sys_write(h->kernel_fd, (const char *)buf, (int)count);
|
n = sys_write(h->kernel_fd, (const char *)buf, (int)count);
|
||||||
} else {
|
} else {
|
||||||
n = sys_write_fs(h->kernel_fd, buf, (uint32_t)count);
|
n = sys_write_fs(h->kernel_fd, buf, (uint32_t)count);
|
||||||
|
if (n < 0) {
|
||||||
|
n = sys_write(h->kernel_fd, (const char *)buf, (int)count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
|
|
@ -442,7 +452,7 @@ __attribute__((weak)) int isatty(int fd) {
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return (h->type == HANDLE_KERNEL_FD && h->kernel_fd <= 2) ? 1 : 0;
|
return (h->type == HANDLE_KERNEL_FD && _b_is_stdio_handle(h)) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((weak)) int fstat(int fd, struct stat *statbuf) {
|
__attribute__((weak)) int fstat(int fd, struct stat *statbuf) {
|
||||||
|
|
@ -471,31 +481,38 @@ __attribute__((weak)) int fstat(int fd, struct stat *statbuf) {
|
||||||
|
|
||||||
__attribute__((weak)) int dup(int oldfd) {
|
__attribute__((weak)) int dup(int oldfd) {
|
||||||
fd_handle_t *h;
|
fd_handle_t *h;
|
||||||
|
fd_handle_t *src;
|
||||||
int newfd;
|
int newfd;
|
||||||
int newkfd;
|
int newkfd;
|
||||||
_b_fd_init();
|
_b_fd_init();
|
||||||
|
|
||||||
h = _b_get_handle(oldfd);
|
src = _b_get_handle(oldfd);
|
||||||
if (!h) {
|
if (!src) {
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (h->type != HANDLE_KERNEL_FD) {
|
if (src->type != HANDLE_KERNEL_FD) {
|
||||||
errno = ENOTSUP;
|
errno = ENOTSUP;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
newkfd = sys_dup(h->kernel_fd);
|
newkfd = sys_dup(src->kernel_fd);
|
||||||
if (newkfd < 0) {
|
if (newkfd < 0) {
|
||||||
errno = EBADF;
|
if (_b_is_stdio_handle(src)) {
|
||||||
return -1;
|
newkfd = src->kernel_fd;
|
||||||
|
} else {
|
||||||
|
errno = EBADF;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newfd = _b_alloc_fd_from(0);
|
newfd = _b_alloc_fd_from(0);
|
||||||
if (newfd < 0) {
|
if (newfd < 0) {
|
||||||
sys_close(newkfd);
|
if (newkfd >= 3) {
|
||||||
errno = EBUSY;
|
sys_close(newkfd);
|
||||||
|
}
|
||||||
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -510,19 +527,20 @@ __attribute__((weak)) int dup(int oldfd) {
|
||||||
h->refcount = 1;
|
h->refcount = 1;
|
||||||
h->flags = O_RDWR;
|
h->flags = O_RDWR;
|
||||||
h->kernel_fd = newkfd;
|
h->kernel_fd = newkfd;
|
||||||
|
h->owns_kernel_fd = (newkfd != src->kernel_fd) ? 1 : 0;
|
||||||
h->pipe = NULL;
|
h->pipe = NULL;
|
||||||
g_fd_table[newfd] = h;
|
g_fd_table[newfd] = h;
|
||||||
return newfd;
|
return newfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((weak)) int dup2(int oldfd, int newfd) {
|
__attribute__((weak)) int dup2(int oldfd, int newfd) {
|
||||||
fd_handle_t *h;
|
fd_handle_t *src;
|
||||||
fd_handle_t *nh;
|
fd_handle_t *nh;
|
||||||
int newkfd;
|
int kfd_res;
|
||||||
_b_fd_init();
|
_b_fd_init();
|
||||||
|
|
||||||
h = _b_get_handle(oldfd);
|
src = _b_get_handle(oldfd);
|
||||||
if (!h || newfd < 0 || newfd >= POSIX_MAX_FDS) {
|
if (!src || newfd < 0 || newfd >= POSIX_MAX_FDS) {
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -531,36 +549,48 @@ __attribute__((weak)) int dup2(int oldfd, int newfd) {
|
||||||
return newfd;
|
return newfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (h->type != HANDLE_KERNEL_FD) {
|
if (src->type != HANDLE_KERNEL_FD) {
|
||||||
errno = ENOTSUP;
|
errno = ENOTSUP;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_fd_table[newfd]) {
|
// Force kernel to update its FD table for the new slot
|
||||||
if (close(newfd) != 0) {
|
kfd_res = sys_dup2(src->kernel_fd, newfd);
|
||||||
return -1;
|
if (kfd_res < 0) {
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
newkfd = sys_dup(h->kernel_fd);
|
|
||||||
if (newkfd < 0) {
|
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
nh = (fd_handle_t *)malloc(sizeof(fd_handle_t));
|
// If newfd was already open in libc, we need to replace its handle
|
||||||
if (!nh) {
|
if (g_fd_table[newfd] && !_b_is_stdio_handle(g_fd_table[newfd])) {
|
||||||
errno = ENOMEM;
|
close(newfd);
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nh->type = HANDLE_KERNEL_FD;
|
// If it's a stdio handle, we update it in place
|
||||||
nh->refcount = 1;
|
if (newfd >= 0 && newfd <= 2) {
|
||||||
nh->flags = h->flags;
|
nh = &g_stdio_handles[newfd];
|
||||||
nh->kernel_fd = newkfd;
|
nh->type = HANDLE_KERNEL_FD;
|
||||||
nh->pipe = NULL;
|
nh->kernel_fd = newfd;
|
||||||
|
nh->flags = src->flags;
|
||||||
|
nh->refcount = 1;
|
||||||
|
nh->owns_kernel_fd = 0;
|
||||||
|
nh->pipe = NULL;
|
||||||
|
g_fd_table[newfd] = nh;
|
||||||
|
} else {
|
||||||
|
nh = (fd_handle_t *)malloc(sizeof(fd_handle_t));
|
||||||
|
if (!nh) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
nh->type = HANDLE_KERNEL_FD;
|
||||||
|
nh->refcount = 1;
|
||||||
|
nh->flags = src->flags;
|
||||||
|
nh->kernel_fd = newfd;
|
||||||
|
nh->owns_kernel_fd = 1;
|
||||||
|
nh->pipe = NULL;
|
||||||
|
g_fd_table[newfd] = nh;
|
||||||
|
}
|
||||||
|
|
||||||
g_fd_table[newfd] = nh;
|
|
||||||
return newfd;
|
return newfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue