mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 10:48:38 +00:00
Compare commits
No commits in common. "d4522cab2100644a426742485eb49045a14879a7" and "57bc840bcba15da115c50edbc7db5744badcfa1e" have entirely different histories.
d4522cab21
...
57bc840bcb
9 changed files with 310 additions and 835 deletions
238
Makefile
238
Makefile
|
|
@ -36,21 +36,43 @@ 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 := $(shell find $(SRC_DIR) -type f -name '*.c' \
|
C_SOURCES = $(wildcard $(SRC_DIR)/core/*.c) \
|
||||||
! -path '$(SRC_DIR)/userland/*' \
|
$(wildcard $(SRC_DIR)/sys/*.c) \
|
||||||
! -path '*/third_party/lwip/netif/slipif.c')
|
$(wildcard $(SRC_DIR)/mem/*.c) \
|
||||||
ASM_SOURCES := $(shell find $(SRC_DIR) -type f -name '*.asm' ! -path '$(SRC_DIR)/userland/*')
|
$(wildcard $(SRC_DIR)/dev/*.c) \
|
||||||
|
$(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
|
||||||
|
|
||||||
OBJ_FILES := $(patsubst $(SRC_DIR)/%.c, $(BUILD_DIR)/%.o, $(C_SOURCES)) \
|
ASM_SOURCES = $(wildcard $(SRC_DIR)/arch/*.asm)
|
||||||
$(patsubst $(SRC_DIR)/%.asm, $(BUILD_DIR)/%.o, $(ASM_SOURCES))
|
OBJ_FILES = $(patsubst $(SRC_DIR)/core/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/core/*.c)) \
|
||||||
|
$(patsubst $(SRC_DIR)/sys/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/sys/*.c)) \
|
||||||
INCLUDE_DIRS := $(shell find $(SRC_DIR) -type d ! -path '$(SRC_DIR)/userland*')
|
$(patsubst $(SRC_DIR)/mem/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/mem/*.c)) \
|
||||||
INCLUDES := $(patsubst %, -I%, $(INCLUDE_DIRS))
|
$(patsubst $(SRC_DIR)/dev/%.c, $(BUILD_DIR)/%.o, $(wildcard $(SRC_DIR)/dev/*.c)) \
|
||||||
|
$(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 \
|
||||||
$(INCLUDES)
|
-I$(SRC_DIR) -I$(SRC_DIR)/net/third_party/lwip -I$(SRC_DIR)/core \
|
||||||
|
-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
|
||||||
|
|
@ -72,52 +94,118 @@ 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)\n"; \
|
printf "$(YELLOW)[LIMINE] Limine binaries missing or invalid. Cloning v$(LIMINE_VERSION)-binary...$(RESET)"; \
|
||||||
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)\n"; \
|
printf "$(YELLOW)[LIMINE] Existing Limine binaries found.$(RESET)"; \
|
||||||
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)\n"; \
|
printf "$(YELLOW)[LIMINE] Copying limine.h...$(RESET)"; \
|
||||||
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)\n"; \
|
printf "$(YELLOW)[LIMINE] limine.h already present.$(RESET)"; \
|
||||||
fi
|
fi
|
||||||
@printf "$(YELLOW)[LIMINE] Building Limine host utility...$(RESET)\n"
|
@printf "$(YELLOW)[LIMINE] Building Limine host utility...$(RESET)"
|
||||||
$(MAKE) -C limine
|
$(MAKE) -C limine
|
||||||
@printf "$(GREEN)[OK] Limine setup complete.$(RESET)\n"
|
@printf "$(GREEN)[OK] Limine setup complete.$(RESET)"
|
||||||
|
|
||||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c | $(BUILD_DIR) limine-setup
|
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c | $(BUILD_DIR) limine-setup
|
||||||
@printf "$(YELLOW)[CC]$(RESET) $< -> $@\n"
|
@printf "$(YELLOW)[CC]$(RESET) $< -> $@"
|
||||||
@mkdir -p $(dir $@)
|
mkdir -p $(dir $@)
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.asm | $(BUILD_DIR)
|
$(BUILD_DIR)/%.o: $(SRC_DIR)/core/%.c | $(BUILD_DIR) limine-setup
|
||||||
@printf "$(YELLOW)[ASM]$(RESET) $< -> $@\n"
|
@printf "$(YELLOW)[CC]$(RESET)[core] $< -> $@"
|
||||||
@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: $@\n"
|
@printf "$(YELLOW)[LD]$(RESET) Linking kernel ELF: $@"
|
||||||
$(LD) $(LDFLAGS) -o $@ $(OBJ_FILES)
|
$(LD) $(LDFLAGS) -o $@ $(OBJ_FILES)
|
||||||
@printf "$(GREEN)[OK]$(RESET) Kernel ELF built: $@\n"
|
@printf "$(GREEN)[OK]$(RESET) Kernel ELF built: $@"
|
||||||
$(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.\n"
|
@printf "$(GREEN)[OK]$(RESET) Userland build complete."
|
||||||
|
|
||||||
$(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...\n"
|
@printf "$(YELLOW)[INITRD]$(RESET) Cleaning previous initrd directory..."
|
||||||
rm -rf $(BUILD_DIR)/initrd
|
rm -rf $(BUILD_DIR)/initrd
|
||||||
|
|
||||||
@printf "$(YELLOW)[INITRD]$(RESET) Creating directory structure...\n"
|
@printf "$(YELLOW)[INITRD]$(RESET) Creating directory structure..."
|
||||||
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
|
||||||
|
|
@ -144,21 +232,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...\n"
|
@printf "$(YELLOW)[COPY]$(RESET) Limine binaries + kernel for installer..."
|
||||||
@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...\n"
|
@printf "$(YELLOW)[COPY]$(RESET) Userland binaries..."
|
||||||
@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\n"; \
|
printf " -> $$f"; \
|
||||||
cp "$$f" $(BUILD_DIR)/initrd/bin/; \
|
cp "$$f" $(BUILD_DIR)/initrd/bin/; \
|
||||||
fi \
|
fi \
|
||||||
done
|
done
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) TCC support files...\n"
|
@printf "$(YELLOW)[COPY]$(RESET) TCC support files..."
|
||||||
@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/
|
||||||
|
|
@ -175,120 +263,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...\n"
|
@printf "$(YELLOW)[COPY]$(RESET) Wallpapers..."
|
||||||
@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\n"; \
|
printf " -> $$f"; \
|
||||||
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...\n"
|
@printf "$(YELLOW)[COPY]$(RESET) GIF assets..."
|
||||||
@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\n"; \
|
printf " -> $$f"; \
|
||||||
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...\n"
|
@printf "$(YELLOW)[COPY]$(RESET) Colloid icons..."
|
||||||
@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\n"; \
|
printf " -> $$src"; \
|
||||||
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...\n"
|
@printf "$(YELLOW)[COPY]$(RESET) BoredOS icons..."
|
||||||
@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\n"; \
|
printf " -> $$f"; \
|
||||||
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...\n"
|
@printf "$(YELLOW)[COPY]$(RESET) Branding assets..."
|
||||||
@cp -r branding/* $(BUILD_DIR)/initrd/Library/images/branding/
|
@cp -r branding/* $(BUILD_DIR)/initrd/Library/images/branding/
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) Fonts...\n"
|
@printf "$(YELLOW)[COPY]$(RESET) Fonts..."
|
||||||
@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\n"; \
|
printf " -> $$f"; \
|
||||||
cp "$$f" $(BUILD_DIR)/initrd/Library/Fonts/; \
|
cp "$$f" $(BUILD_DIR)/initrd/Library/Fonts/; \
|
||||||
fi \
|
fi \
|
||||||
done
|
done
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) Emoji fonts...\n"
|
@printf "$(YELLOW)[COPY]$(RESET) Emoji fonts..."
|
||||||
@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\n"; \
|
printf " -> $$f"; \
|
||||||
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...\n"
|
@printf "$(YELLOW)[COPY]$(RESET) bsh configuration..."
|
||||||
@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/bshrc ]; then printf " -> bshrc"; cp $(SRC_DIR)/library/bsh/bshrc $(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/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/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/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/conf/sysfetch.cfg ]; then printf " -> sysfetch.cfg\n"; 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"; cp $(SRC_DIR)/library/conf/sysfetch.cfg $(BUILD_DIR)/initrd/Library/conf/; fi
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) DOOM assets...\n"
|
@printf "$(YELLOW)[COPY]$(RESET) DOOM assets..."
|
||||||
@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
|
@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
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) ASCII art...\n"
|
@printf "$(YELLOW)[COPY]$(RESET) ASCII art..."
|
||||||
@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
|
@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
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) Documentation...\n"
|
@printf "$(YELLOW)[COPY]$(RESET) Documentation..."
|
||||||
@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\n"; \
|
printf " -> $$f"; \
|
||||||
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...\n"
|
@printf "$(YELLOW)[COPY]$(RESET) Root files..."
|
||||||
@if [ -f README.md ]; then printf " -> README.md\n"; cp README.md $(BUILD_DIR)/initrd/; fi
|
@if [ -f README.md ]; then printf " -> README.md"; cp README.md $(BUILD_DIR)/initrd/; fi
|
||||||
@if [ -f LICENSE ]; then printf " -> LICENSE\n"; cp LICENSE $(BUILD_DIR)/initrd/; fi
|
@if [ -f LICENSE ]; then printf " -> LICENSE"; cp LICENSE $(BUILD_DIR)/initrd/; fi
|
||||||
@if [ -f limine.conf ]; then printf " -> limine.conf\n"; cp limine.conf $(BUILD_DIR)/initrd/; fi
|
@if [ -f limine.conf ]; then printf " -> limine.conf"; cp limine.conf $(BUILD_DIR)/initrd/; fi
|
||||||
|
|
||||||
@printf "$(YELLOW)[TAR]$(RESET) Creating initrd.tar...\n"
|
@printf "$(YELLOW)[TAR]$(RESET) Creating initrd.tar..."
|
||||||
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\n"
|
@printf "$(GREEN)[OK]$(RESET) Initrd created: $(BUILD_DIR)/initrd.tar"
|
||||||
|
|
||||||
$(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...\n"
|
@printf "$(YELLOW)[ISO]$(RESET) Cleaning previous ISO root..."
|
||||||
rm -rf $(ISO_DIR)
|
rm -rf $(ISO_DIR)
|
||||||
|
|
||||||
@printf "$(YELLOW)[ISO]$(RESET) Creating ISO directory structure...\n"
|
@printf "$(YELLOW)[ISO]$(RESET) Creating ISO directory structure..."
|
||||||
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...\n"
|
@printf "$(YELLOW)[COPY]$(RESET) Kernel ELF..."
|
||||||
cp $(KERNEL_ELF) $(ISO_DIR)/
|
cp $(KERNEL_ELF) $(ISO_DIR)/
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) Limine config...\n"
|
@printf "$(YELLOW)[COPY]$(RESET) Limine config..."
|
||||||
cp limine.conf $(ISO_DIR)/
|
cp limine.conf $(ISO_DIR)/
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) Initrd...\n"
|
@printf "$(YELLOW)[COPY]$(RESET) Initrd..."
|
||||||
cp $(BUILD_DIR)/initrd.tar $(ISO_DIR)/
|
cp $(BUILD_DIR)/initrd.tar $(ISO_DIR)/
|
||||||
|
|
||||||
@printf "$(YELLOW)[CONFIG]$(RESET) Adding initrd module path...\n"
|
@printf "$(YELLOW)[CONFIG]$(RESET) Adding initrd module path..."
|
||||||
printf " module_path: boot():/initrd.tar\n" >> $(ISO_DIR)/limine.conf
|
printf " module_path: boot():/initrd.tar" >> $(ISO_DIR)/limine.conf
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) Optional splash image...\n"
|
@printf "$(YELLOW)[COPY]$(RESET) Optional splash image..."
|
||||||
@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
|
@if [ -f branding/splash.jpg ]; then printf " -> splash.jpg"; cp branding/splash.jpg $(ISO_DIR)/splash.jpg; else printf " -> no splash.jpg found"; fi
|
||||||
|
|
||||||
@printf "$(YELLOW)[COPY]$(RESET) Limine boot files...\n"
|
@printf "$(YELLOW)[COPY]$(RESET) Limine boot files..."
|
||||||
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...\n"
|
@printf "$(YELLOW)[COPY]$(RESET) EFI bootloaders..."
|
||||||
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/
|
||||||
|
|
||||||
|
|
@ -299,15 +387,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...\n"
|
@printf "$(YELLOW)[LIMINE]$(RESET) Installing BIOS bootloader..."
|
||||||
./limine/limine bios-install $(ISO_IMAGE)
|
./limine/limine bios-install $(ISO_IMAGE)
|
||||||
@printf "$(GREEN)[OK]$(RESET) ISO image ready: $(ISO_IMAGE)\n"
|
@printf "$(GREEN)[OK]$(RESET) ISO image ready: $(ISO_IMAGE)"
|
||||||
|
|
||||||
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.\n"
|
@printf "$(GREEN)[OK]$(RESET) Clean complete."
|
||||||
|
|
||||||
disk.qcow2:
|
disk.qcow2:
|
||||||
$(call PRINT_STEP,CREATING 10GB EXPANDABLE DISK IMAGE)
|
$(call PRINT_STEP,CREATING 10GB EXPANDABLE DISK IMAGE)
|
||||||
|
|
@ -368,7 +456,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...\n"; \
|
printf "$(YELLOW)[UEFI]$(RESET) Creating local NVRAM vars..."; \
|
||||||
cp $(OVMF_VARS_TMPL) $(OVMF_VARS); \
|
cp $(OVMF_VARS_TMPL) $(OVMF_VARS); \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
||||||
67
README.md
67
README.md
|
|
@ -68,6 +68,73 @@
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
|
## 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
|
## ☕ Support the Journey
|
||||||
|
|
||||||
If you find BoredOS interesting or useful, consider fueling development with a coffee!
|
If you find BoredOS interesting or useful, consider fueling development with a coffee!
|
||||||
|
|
|
||||||
|
|
@ -7,88 +7,11 @@ 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).
|
||||||
- **Redirection**:
|
- **Output 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
|
||||||
|
|
||||||
|
|
@ -126,12 +49,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. |
|
| `lsblk` | List block devices and partitions with size, type, filesystem, label, and flags. |
|
||||||
| `du` | Report disk usage for files and directories. |
|
| `du` | Report disk usage for files and directories, recursively. |
|
||||||
| `sysfetch` | Display system information and BoredOS branding. |
|
| `sysfetch` | Display system and hardware information. |
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 830 KiB |
|
|
@ -302,40 +302,6 @@ 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;
|
||||||
|
|
@ -348,6 +314,7 @@ 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,7 +17,6 @@
|
||||||
#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,12 +1102,6 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1145,12 +1139,6 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@
|
||||||
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
|
// 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.
|
// This header needs to maintain in any file it is present in, as per the GPL license terms.
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <syscall.h>
|
#include <syscall.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "utf-8.h"
|
#include "utf-8.h"
|
||||||
|
|
@ -326,17 +324,6 @@ static void reset_color(void) {
|
||||||
sys_set_text_color(g_color_default);
|
sys_set_text_color(g_color_default);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void shell_write(const char *buf, int len) {
|
|
||||||
if (!buf || len <= 0) return;
|
|
||||||
write(1, buf, (size_t)len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void shell_writeln(const char *buf) {
|
|
||||||
if (!buf) return;
|
|
||||||
shell_write(buf, (int)strlen(buf));
|
|
||||||
shell_write("\n", 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void prompt_emit(const char *text, int len, char *out, int *out_idx, int max_len, bool do_write) {
|
static void prompt_emit(const char *text, int len, char *out, int *out_idx, int max_len, bool do_write) {
|
||||||
if (!text || len <= 0) return;
|
if (!text || len <= 0) return;
|
||||||
if (do_write) sys_write(1, text, len);
|
if (do_write) sys_write(1, text, len);
|
||||||
|
|
@ -910,10 +897,9 @@ static void show_matches(const char *prompt_tmpl, const char *line, int len, cha
|
||||||
redraw_input(prompt_tmpl, line, len, len);
|
redraw_input(prompt_tmpl, line, len, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int wait_for_pid(int pid) {
|
static void wait_for_pid(int pid) {
|
||||||
int status = 0;
|
|
||||||
while (1) {
|
while (1) {
|
||||||
int rc = sys_waitpid(pid, &status, 1);
|
int rc = sys_waitpid(pid, NULL, 1);
|
||||||
if (rc == pid || rc < 0) break;
|
if (rc == pid || rc < 0) break;
|
||||||
if (g_tty_id >= 0) {
|
if (g_tty_id >= 0) {
|
||||||
int fg = sys_tty_get_fg(g_tty_id);
|
int fg = sys_tty_get_fg(g_tty_id);
|
||||||
|
|
@ -921,13 +907,6 @@ static int wait_for_pid(int pid) {
|
||||||
}
|
}
|
||||||
sleep(10);
|
sleep(10);
|
||||||
}
|
}
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int bsh_open_file(const char *path, const char *mode, bool *is_kernel) {
|
|
||||||
if (!path || !mode) return -1;
|
|
||||||
if (is_kernel) *is_kernel = true;
|
|
||||||
return sys_open(path, mode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cmd_clear(void) {
|
static void cmd_clear(void) {
|
||||||
|
|
@ -948,7 +927,7 @@ static int builtin_cd(int argc, char *argv[]) {
|
||||||
static int builtin_pwd(void) {
|
static int builtin_pwd(void) {
|
||||||
char cwd[256];
|
char cwd[256];
|
||||||
if (getcwd(cwd, sizeof(cwd))) {
|
if (getcwd(cwd, sizeof(cwd))) {
|
||||||
shell_writeln(cwd);
|
printf("%s\n", cwd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
|
@ -956,10 +935,10 @@ static int builtin_pwd(void) {
|
||||||
|
|
||||||
static int builtin_echo(int argc, char *argv[]) {
|
static int builtin_echo(int argc, char *argv[]) {
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
if (i > 1) shell_write(" ", 1);
|
if (i > 1) sys_write(1, " ", 1);
|
||||||
shell_write(argv[i], (int)strlen(argv[i]));
|
sys_write(1, argv[i], (int)strlen(argv[i]));
|
||||||
}
|
}
|
||||||
shell_write("\n", 1);
|
sys_write(1, "\n", 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -977,7 +956,7 @@ static int builtin_ls(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
if (!info.is_directory) {
|
if (!info.is_directory) {
|
||||||
set_color(g_color_file);
|
set_color(g_color_file);
|
||||||
shell_writeln(info.name);
|
printf("%s\n", info.name);
|
||||||
reset_color();
|
reset_color();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -994,18 +973,12 @@ static int builtin_ls(int argc, char *argv[]) {
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
if (entries[i].is_directory) {
|
if (entries[i].is_directory) {
|
||||||
set_color(g_color_dir);
|
set_color(g_color_dir);
|
||||||
shell_write("[DIR] ", 7);
|
printf("[DIR] %s\n", entries[i].name);
|
||||||
shell_writeln(entries[i].name);
|
|
||||||
} else {
|
} else {
|
||||||
set_color(g_color_file);
|
set_color(g_color_file);
|
||||||
shell_write("[FILE] ", 7);
|
printf("[FILE] %s", entries[i].name);
|
||||||
shell_write(entries[i].name, (int)strlen(entries[i].name));
|
|
||||||
set_color(g_color_size);
|
set_color(g_color_size);
|
||||||
char size_buf[32];
|
printf(" (%d bytes)\n", entries[i].size);
|
||||||
itoa((int)entries[i].size, size_buf);
|
|
||||||
shell_write(" (", 2);
|
|
||||||
shell_write(size_buf, (int)strlen(size_buf));
|
|
||||||
shell_write(" bytes)\n", 8);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
reset_color();
|
reset_color();
|
||||||
|
|
@ -1014,12 +987,10 @@ static int builtin_ls(int argc, char *argv[]) {
|
||||||
|
|
||||||
static int builtin_cat(int argc, char *argv[]) {
|
static int builtin_cat(int argc, char *argv[]) {
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
char buffer[4096];
|
set_color(g_color_error);
|
||||||
int bytes;
|
printf("Usage: cat <file>\n");
|
||||||
while ((bytes = read(0, buffer, sizeof(buffer))) > 0) {
|
reset_color();
|
||||||
shell_write(buffer, bytes);
|
return 1;
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
|
|
@ -1033,7 +1004,7 @@ static int builtin_cat(int argc, char *argv[]) {
|
||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
int bytes;
|
int bytes;
|
||||||
while ((bytes = sys_read(fd, buffer, sizeof(buffer))) > 0) {
|
while ((bytes = sys_read(fd, buffer, sizeof(buffer))) > 0) {
|
||||||
shell_write(buffer, bytes);
|
sys_write(1, buffer, bytes);
|
||||||
}
|
}
|
||||||
sys_close(fd);
|
sys_close(fd);
|
||||||
}
|
}
|
||||||
|
|
@ -1259,20 +1230,17 @@ static int builtin_man(int argc, char *argv[]) {
|
||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
int bytes;
|
int bytes;
|
||||||
while ((bytes = sys_read(fd, buffer, sizeof(buffer))) > 0) {
|
while ((bytes = sys_read(fd, buffer, sizeof(buffer))) > 0) {
|
||||||
shell_write(buffer, bytes);
|
sys_write(1, buffer, bytes);
|
||||||
}
|
}
|
||||||
sys_close(fd);
|
sys_close(fd);
|
||||||
shell_write("\n", 1);
|
printf("\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int builtin_alias(int argc, char *argv[]) {
|
static int builtin_alias(int argc, char *argv[]) {
|
||||||
if (argc == 1) {
|
if (argc == 1) {
|
||||||
for (int i = 0; i < g_alias_count; i++) {
|
for (int i = 0; i < g_alias_count; i++) {
|
||||||
shell_write("alias ", 6);
|
printf("alias %s=%s\n", g_aliases[i].name, g_aliases[i].value);
|
||||||
shell_write(g_aliases[i].name, (int)strlen(g_aliases[i].name));
|
|
||||||
shell_write("=", 1);
|
|
||||||
shell_writeln(g_aliases[i].value);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1283,10 +1251,7 @@ static int builtin_alias(int argc, char *argv[]) {
|
||||||
if (*eq != '=') {
|
if (*eq != '=') {
|
||||||
const char *val = alias_get(argv[i]);
|
const char *val = alias_get(argv[i]);
|
||||||
if (val) {
|
if (val) {
|
||||||
shell_write("alias ", 6);
|
printf("alias %s=%s\n", argv[i], val);
|
||||||
shell_write(argv[i], (int)strlen(argv[i]));
|
|
||||||
shell_write("=", 1);
|
|
||||||
shell_writeln(val);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
set_color(g_color_error);
|
set_color(g_color_error);
|
||||||
|
|
@ -1346,220 +1311,19 @@ static int execute_builtin(int argc, char *argv[]) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_builtin_name(const char *name) {
|
static int execute_line_inner(const char *line, int depth) {
|
||||||
return str_eq(name, "cd") || str_eq(name, "pwd") || str_eq(name, "ls") ||
|
if (!line || !line[0]) return 0;
|
||||||
str_eq(name, "cat") || str_eq(name, "echo") || str_eq(name, "clear") ||
|
|
||||||
str_eq(name, "mkdir") || str_eq(name, "rm") || str_eq(name, "touch") ||
|
|
||||||
str_eq(name, "cp") || str_eq(name, "mv") || str_eq(name, "man") ||
|
|
||||||
str_eq(name, "alias") || str_eq(name, "unalias") || str_eq(name, ".") ||
|
|
||||||
str_eq(name, "exit");
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
TOK_WORD = 0,
|
|
||||||
TOK_PIPE,
|
|
||||||
TOK_GT,
|
|
||||||
TOK_GTGT,
|
|
||||||
TOK_LT,
|
|
||||||
TOK_AMP,
|
|
||||||
TOK_ANDAND,
|
|
||||||
TOK_OROR,
|
|
||||||
TOK_SEMI,
|
|
||||||
TOK_END
|
|
||||||
} bsh_tok_type_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
bsh_tok_type_t type;
|
|
||||||
char text[MAX_MATCH_LEN];
|
|
||||||
} bsh_token_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char *argv[MAX_ARGS];
|
|
||||||
int argc;
|
|
||||||
char *redir_in;
|
|
||||||
char *redir_out;
|
|
||||||
bool redir_append;
|
|
||||||
} bsh_simple_cmd_t;
|
|
||||||
|
|
||||||
#define MAX_TOKENS 128
|
|
||||||
#define MAX_PIPE_CMDS 16
|
|
||||||
|
|
||||||
static bool is_op_char(char c) {
|
|
||||||
return c == '|' || c == '&' || c == ';' || c == '<' || c == '>';
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_syntax_error(const char *msg) {
|
|
||||||
set_color(g_color_error);
|
|
||||||
printf("bsh: syntax error: %s\n", msg);
|
|
||||||
reset_color();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void alias_snapshot_save(alias_t out_aliases[], int *out_count) {
|
|
||||||
if (!out_aliases || !out_count) return;
|
|
||||||
*out_count = g_alias_count;
|
|
||||||
for (int i = 0; i < g_alias_count && i < MAX_ALIASES; i++) {
|
|
||||||
out_aliases[i] = g_aliases[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void alias_snapshot_restore(const alias_t saved_aliases[], int saved_count) {
|
|
||||||
g_alias_count = 0;
|
|
||||||
if (!saved_aliases || saved_count <= 0) return;
|
|
||||||
int copy_count = saved_count < MAX_ALIASES ? saved_count : MAX_ALIASES;
|
|
||||||
for (int i = 0; i < copy_count; i++) {
|
|
||||||
g_aliases[i] = saved_aliases[i];
|
|
||||||
}
|
|
||||||
g_alias_count = copy_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int tokenize_line(const char *line, bsh_token_t toks[], int max_toks) {
|
|
||||||
if (!line || !toks || max_toks < 2) return -1;
|
|
||||||
int tcount = 0;
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
while (line[i]) {
|
|
||||||
while (line[i] == ' ' || line[i] == '\t') i++;
|
|
||||||
if (!line[i]) break;
|
|
||||||
if (tcount >= max_toks - 1) {
|
|
||||||
print_syntax_error("too many tokens");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line[i] == '&' && line[i + 1] == '&') {
|
|
||||||
toks[tcount].type = TOK_ANDAND;
|
|
||||||
toks[tcount].text[0] = 0;
|
|
||||||
tcount++;
|
|
||||||
i += 2;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (line[i] == '|' && line[i + 1] == '|') {
|
|
||||||
toks[tcount].type = TOK_OROR;
|
|
||||||
toks[tcount].text[0] = 0;
|
|
||||||
tcount++;
|
|
||||||
i += 2;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (line[i] == '>' && line[i + 1] == '>') {
|
|
||||||
toks[tcount].type = TOK_GTGT;
|
|
||||||
toks[tcount].text[0] = 0;
|
|
||||||
tcount++;
|
|
||||||
i += 2;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line[i] == '|') {
|
|
||||||
toks[tcount].type = TOK_PIPE;
|
|
||||||
toks[tcount].text[0] = 0;
|
|
||||||
tcount++;
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (line[i] == '&') {
|
|
||||||
toks[tcount].type = TOK_AMP;
|
|
||||||
toks[tcount].text[0] = 0;
|
|
||||||
tcount++;
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (line[i] == ';') {
|
|
||||||
toks[tcount].type = TOK_SEMI;
|
|
||||||
toks[tcount].text[0] = 0;
|
|
||||||
tcount++;
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (line[i] == '<') {
|
|
||||||
toks[tcount].type = TOK_LT;
|
|
||||||
toks[tcount].text[0] = 0;
|
|
||||||
tcount++;
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (line[i] == '>') {
|
|
||||||
toks[tcount].type = TOK_GT;
|
|
||||||
toks[tcount].text[0] = 0;
|
|
||||||
tcount++;
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
toks[tcount].type = TOK_WORD;
|
|
||||||
int out = 0;
|
|
||||||
while (line[i] && line[i] != ' ' && line[i] != '\t' && !is_op_char(line[i])) {
|
|
||||||
if (line[i] == '"' || line[i] == '\'') {
|
|
||||||
char quote = line[i++];
|
|
||||||
while (line[i] && line[i] != quote) {
|
|
||||||
if (out < MAX_MATCH_LEN - 1) toks[tcount].text[out++] = line[i];
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
if (line[i] == quote) i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (out < MAX_MATCH_LEN - 1) toks[tcount].text[out++] = line[i];
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
toks[tcount].text[out] = 0;
|
|
||||||
if (out == 0) {
|
|
||||||
print_syntax_error("unexpected token");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
tcount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
toks[tcount].type = TOK_END;
|
|
||||||
toks[tcount].text[0] = 0;
|
|
||||||
return tcount;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool parse_simple_command(bsh_token_t toks[], int *idx, bsh_simple_cmd_t *cmd) {
|
|
||||||
if (!toks || !idx || !cmd) return false;
|
|
||||||
cmd->argc = 0;
|
|
||||||
cmd->redir_in = NULL;
|
|
||||||
cmd->redir_out = NULL;
|
|
||||||
cmd->redir_append = false;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
bsh_tok_type_t t = toks[*idx].type;
|
|
||||||
if (t == TOK_WORD) {
|
|
||||||
if (cmd->argc >= MAX_ARGS - 1) {
|
|
||||||
print_syntax_error("too many arguments");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
cmd->argv[cmd->argc++] = toks[*idx].text;
|
|
||||||
(*idx)++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (t == TOK_LT || t == TOK_GT || t == TOK_GTGT) {
|
|
||||||
bsh_tok_type_t redir = t;
|
|
||||||
(*idx)++;
|
|
||||||
if (toks[*idx].type != TOK_WORD) {
|
|
||||||
print_syntax_error("missing filename after redirection");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (redir == TOK_LT) {
|
|
||||||
cmd->redir_in = toks[*idx].text;
|
|
||||||
} else {
|
|
||||||
cmd->redir_out = toks[*idx].text;
|
|
||||||
cmd->redir_append = (redir == TOK_GTGT);
|
|
||||||
}
|
|
||||||
(*idx)++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd->argv[cmd->argc] = NULL;
|
|
||||||
if (cmd->argc <= 0) {
|
|
||||||
print_syntax_error("expected command");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int execute_argv_inner(int argc, char *argv[], int depth, bool isolated, bool background, bool *want_exit, int *out_pid) {
|
|
||||||
if (argc <= 0) return 0;
|
|
||||||
if (depth > 8) return 1;
|
if (depth > 8) return 1;
|
||||||
if (out_pid) *out_pid = -1;
|
|
||||||
|
char line_copy[MAX_LINE];
|
||||||
|
str_copy(line_copy, line, sizeof(line_copy));
|
||||||
|
trim(line_copy);
|
||||||
|
if (!line_copy[0]) return 0;
|
||||||
|
if (line_copy[0] == '#') return 0;
|
||||||
|
|
||||||
|
char *argv[MAX_ARGS];
|
||||||
|
int argc = split_args(line_copy, argv, MAX_ARGS);
|
||||||
|
if (argc <= 0) return 0;
|
||||||
|
|
||||||
if (!str_eq(argv[0], "alias") && !str_eq(argv[0], "unalias")) {
|
if (!str_eq(argv[0], "alias") && !str_eq(argv[0], "unalias")) {
|
||||||
const char *alias_val = alias_get(argv[0]);
|
const char *alias_val = alias_get(argv[0]);
|
||||||
|
|
@ -1573,37 +1337,13 @@ static int execute_argv_inner(int argc, char *argv[], int depth, bool isolated,
|
||||||
str_append(expanded, " ", sizeof(expanded));
|
str_append(expanded, " ", sizeof(expanded));
|
||||||
str_append(expanded, tail, sizeof(expanded));
|
str_append(expanded, tail, sizeof(expanded));
|
||||||
}
|
}
|
||||||
|
return execute_line_inner(expanded, depth + 1);
|
||||||
char split_buf[MAX_LINE];
|
|
||||||
str_copy(split_buf, expanded, sizeof(split_buf));
|
|
||||||
char *expanded_argv[MAX_ARGS];
|
|
||||||
int expanded_argc = split_args(split_buf, expanded_argv, MAX_ARGS);
|
|
||||||
if (expanded_argc <= 0) return 0;
|
|
||||||
return execute_argv_inner(expanded_argc, expanded_argv, depth + 1, isolated, background, want_exit, out_pid);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int bi = -1;
|
int bi = execute_builtin(argc, argv);
|
||||||
if (isolated) {
|
if (bi == 2) return 2;
|
||||||
alias_t saved_aliases[MAX_ALIASES];
|
if (bi >= 0) return 0;
|
||||||
int saved_alias_count = 0;
|
|
||||||
char saved_cwd[256];
|
|
||||||
bool had_cwd = getcwd(saved_cwd, sizeof(saved_cwd)) != NULL;
|
|
||||||
|
|
||||||
alias_snapshot_save(saved_aliases, &saved_alias_count);
|
|
||||||
bi = execute_builtin(argc, argv);
|
|
||||||
|
|
||||||
alias_snapshot_restore(saved_aliases, saved_alias_count);
|
|
||||||
if (had_cwd) chdir(saved_cwd);
|
|
||||||
} else {
|
|
||||||
bi = execute_builtin(argc, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bi == 2) {
|
|
||||||
if (!isolated && want_exit) *want_exit = true;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (bi >= 0) return bi == 0 ? 0 : 1;
|
|
||||||
|
|
||||||
char full_path[256];
|
char full_path[256];
|
||||||
int cmd_res = resolve_command(argv[0], full_path, sizeof(full_path));
|
int cmd_res = resolve_command(argv[0], full_path, sizeof(full_path));
|
||||||
|
|
@ -1629,13 +1369,9 @@ static int execute_argv_inner(int argc, char *argv[], int depth, bool isolated,
|
||||||
char args_buf[256];
|
char args_buf[256];
|
||||||
build_args_string(argc, argv, 1, args_buf, sizeof(args_buf));
|
build_args_string(argc, argv, 1, args_buf, sizeof(args_buf));
|
||||||
|
|
||||||
uint64_t spawn_flags = background
|
|
||||||
? (SPAWN_FLAG_INHERIT_TTY | SPAWN_FLAG_BACKGROUND)
|
|
||||||
: (SPAWN_FLAG_TERMINAL | SPAWN_FLAG_INHERIT_TTY);
|
|
||||||
|
|
||||||
int pid = -1;
|
int pid = -1;
|
||||||
for (int attempt = 0; attempt < 5; attempt++) {
|
for (int attempt = 0; attempt < 5; attempt++) {
|
||||||
pid = sys_spawn(full_path, args_buf[0] ? args_buf : NULL, spawn_flags, 0);
|
pid = sys_spawn(full_path, args_buf[0] ? args_buf : NULL, SPAWN_FLAG_TERMINAL | SPAWN_FLAG_INHERIT_TTY, 0);
|
||||||
if (pid >= 0) break;
|
if (pid >= 0) break;
|
||||||
sleep(10);
|
sleep(10);
|
||||||
}
|
}
|
||||||
|
|
@ -1646,278 +1382,14 @@ static int execute_argv_inner(int argc, char *argv[], int depth, bool isolated,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (out_pid) *out_pid = pid;
|
|
||||||
if (background) return 0;
|
|
||||||
|
|
||||||
if (g_tty_id >= 0) sys_tty_set_fg(g_tty_id, pid);
|
if (g_tty_id >= 0) sys_tty_set_fg(g_tty_id, pid);
|
||||||
int status = wait_for_pid(pid);
|
wait_for_pid(pid);
|
||||||
if (g_tty_id >= 0) sys_tty_set_fg(g_tty_id, 0);
|
if (g_tty_id >= 0) sys_tty_set_fg(g_tty_id, 0);
|
||||||
return status;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
static int run_simple_command_with_fds(
|
|
||||||
bsh_simple_cmd_t *cmd,
|
|
||||||
int in_fd,
|
|
||||||
int out_fd,
|
|
||||||
bool isolate,
|
|
||||||
bool background,
|
|
||||||
bool *want_exit,
|
|
||||||
int *out_pid
|
|
||||||
) {
|
|
||||||
if (out_pid) *out_pid = -1;
|
|
||||||
if (!cmd || cmd->argc <= 0) return 0;
|
|
||||||
|
|
||||||
int saved_in = sys_dup(0);
|
|
||||||
int saved_out = sys_dup(1);
|
|
||||||
|
|
||||||
if (saved_in < 0 || saved_out < 0) {
|
|
||||||
if (saved_in >= 0) sys_close(saved_in);
|
|
||||||
if (saved_out >= 0) sys_close(saved_out);
|
|
||||||
set_color(g_color_error);
|
|
||||||
printf("bsh: redirection/pipeline is unavailable in this session\n");
|
|
||||||
reset_color();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int redir_in_fd = -1;
|
|
||||||
int redir_out_fd = -1;
|
|
||||||
bool in_is_kernel = false;
|
|
||||||
bool out_is_kernel = false;
|
|
||||||
int rc = 0;
|
|
||||||
|
|
||||||
// 1. Handle Pipe Input
|
|
||||||
if (in_fd >= 0 && sys_dup2(in_fd, 0) < 0) {
|
|
||||||
set_color(g_color_error);
|
|
||||||
printf("bsh: failed to set pipeline input\n");
|
|
||||||
reset_color();
|
|
||||||
rc = 1;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Handle File Redirection Input (overrides pipe)
|
|
||||||
if (cmd->redir_in) {
|
|
||||||
redir_in_fd = bsh_open_file(cmd->redir_in, "r", &in_is_kernel);
|
|
||||||
if (redir_in_fd < 0 || sys_dup2(redir_in_fd, 0) < 0) {
|
|
||||||
set_color(g_color_error);
|
|
||||||
printf("bsh: cannot read from %s\n", cmd->redir_in);
|
|
||||||
reset_color();
|
|
||||||
rc = 1;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Handle Pipe Output
|
|
||||||
if (out_fd >= 0 && sys_dup2(out_fd, 1) < 0) {
|
|
||||||
set_color(g_color_error);
|
|
||||||
printf("bsh: failed to set pipeline output\n");
|
|
||||||
reset_color();
|
|
||||||
rc = 1;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. Handle File Redirection Output (overrides pipe)
|
|
||||||
if (cmd->redir_out) {
|
|
||||||
const char *mode = cmd->redir_append ? "a" : "w";
|
|
||||||
redir_out_fd = bsh_open_file(cmd->redir_out, mode, &out_is_kernel);
|
|
||||||
if (redir_out_fd < 0 || sys_dup2(redir_out_fd, 1) < 0) {
|
|
||||||
set_color(g_color_error);
|
|
||||||
printf("bsh: cannot write to %s\n", cmd->redir_out);
|
|
||||||
reset_color();
|
|
||||||
rc = 1;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = execute_argv_inner(cmd->argc, cmd->argv, 0, isolate, background, want_exit, out_pid);
|
|
||||||
|
|
||||||
done:
|
|
||||||
if (redir_in_fd >= 0) sys_close(redir_in_fd);
|
|
||||||
if (redir_out_fd >= 0) sys_close(redir_out_fd);
|
|
||||||
|
|
||||||
sys_dup2(saved_in, 0);
|
|
||||||
sys_dup2(saved_out, 1);
|
|
||||||
sys_close(saved_in);
|
|
||||||
sys_close(saved_out);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool parse_pipeline(
|
|
||||||
bsh_token_t toks[],
|
|
||||||
int *idx,
|
|
||||||
bsh_simple_cmd_t cmds[],
|
|
||||||
int *cmd_count
|
|
||||||
) {
|
|
||||||
if (!toks || !idx || !cmds || !cmd_count) return false;
|
|
||||||
*cmd_count = 0;
|
|
||||||
|
|
||||||
if (!parse_simple_command(toks, idx, &cmds[*cmd_count])) return false;
|
|
||||||
(*cmd_count)++;
|
|
||||||
|
|
||||||
while (toks[*idx].type == TOK_PIPE) {
|
|
||||||
(*idx)++;
|
|
||||||
if (*cmd_count >= MAX_PIPE_CMDS) {
|
|
||||||
print_syntax_error("pipeline too long");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!parse_simple_command(toks, idx, &cmds[*cmd_count])) return false;
|
|
||||||
(*cmd_count)++;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int execute_pipeline_cmds(
|
|
||||||
bsh_simple_cmd_t cmds[],
|
|
||||||
int cmd_count,
|
|
||||||
bool background,
|
|
||||||
bool *want_exit
|
|
||||||
) {
|
|
||||||
if (!cmds || cmd_count <= 0) return 0;
|
|
||||||
|
|
||||||
if (cmd_count == 1) {
|
|
||||||
int pid = -1;
|
|
||||||
int res = run_simple_command_with_fds(&cmds[0], -1, -1, background, background, want_exit, &pid);
|
|
||||||
return background ? 0 : res;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pipes[MAX_PIPE_CMDS - 1][2];
|
|
||||||
int pids[MAX_PIPE_CMDS];
|
|
||||||
for (int i = 0; i < cmd_count; i++) pids[i] = -1;
|
|
||||||
|
|
||||||
for (int i = 0; i < cmd_count - 1; i++) {
|
|
||||||
if (pipe(pipes[i]) < 0) {
|
|
||||||
set_color(g_color_error);
|
|
||||||
printf("bsh: failed to create pipe\n");
|
|
||||||
reset_color();
|
|
||||||
for (int j = 0; j < i; j++) {
|
|
||||||
close(pipes[j][0]);
|
|
||||||
close(pipes[j][1]);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < cmd_count; i++) {
|
|
||||||
int in_fd = (i == 0) ? -1 : pipes[i - 1][0];
|
|
||||||
int out_fd = (i == cmd_count - 1) ? -1 : pipes[i][1];
|
|
||||||
|
|
||||||
run_simple_command_with_fds(&cmds[i], in_fd, out_fd, true, true, want_exit, &pids[i]);
|
|
||||||
|
|
||||||
if (in_fd >= 0) close(in_fd);
|
|
||||||
if (out_fd >= 0) close(out_fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (background) return 0;
|
|
||||||
|
|
||||||
int last_status = 0;
|
|
||||||
for (int i = 0; i < cmd_count; i++) {
|
|
||||||
if (pids[i] > 0) {
|
|
||||||
int s = wait_for_pid(pids[i]);
|
|
||||||
if (i == cmd_count - 1) last_status = s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return last_status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool parse_conditional_end_index(bsh_token_t toks[], int start_idx, int *out_end_idx) {
|
|
||||||
int idx = start_idx;
|
|
||||||
bsh_simple_cmd_t cmds[MAX_PIPE_CMDS];
|
|
||||||
int cmd_count = 0;
|
|
||||||
|
|
||||||
if (!parse_pipeline(toks, &idx, cmds, &cmd_count)) return false;
|
|
||||||
|
|
||||||
while (toks[idx].type == TOK_ANDAND || toks[idx].type == TOK_OROR) {
|
|
||||||
idx++;
|
|
||||||
if (!parse_pipeline(toks, &idx, cmds, &cmd_count)) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out_end_idx = idx;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int execute_conditional_range(
|
|
||||||
bsh_token_t toks[],
|
|
||||||
int start_idx,
|
|
||||||
int end_idx,
|
|
||||||
bool background,
|
|
||||||
bool *want_exit
|
|
||||||
) {
|
|
||||||
int idx = start_idx;
|
|
||||||
int status = 0;
|
|
||||||
bool execute_next = true;
|
|
||||||
|
|
||||||
while (idx < end_idx) {
|
|
||||||
bsh_simple_cmd_t cmds[MAX_PIPE_CMDS];
|
|
||||||
int cmd_count = 0;
|
|
||||||
if (!parse_pipeline(toks, &idx, cmds, &cmd_count)) return 1;
|
|
||||||
|
|
||||||
if (execute_next) {
|
|
||||||
status = execute_pipeline_cmds(cmds, cmd_count, background, want_exit);
|
|
||||||
if (*want_exit) return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (idx >= end_idx) break;
|
|
||||||
|
|
||||||
bsh_tok_type_t op = toks[idx].type;
|
|
||||||
idx++;
|
|
||||||
if (op == TOK_ANDAND) {
|
|
||||||
execute_next = (status == 0);
|
|
||||||
} else if (op == TOK_OROR) {
|
|
||||||
execute_next = (status != 0);
|
|
||||||
} else {
|
|
||||||
print_syntax_error("unexpected conditional operator");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int execute_line(const char *line) {
|
static int execute_line(const char *line) {
|
||||||
if (!line || !line[0]) return 0;
|
return execute_line_inner(line, 0);
|
||||||
|
|
||||||
char line_copy[MAX_LINE];
|
|
||||||
str_copy(line_copy, line, sizeof(line_copy));
|
|
||||||
trim(line_copy);
|
|
||||||
if (!line_copy[0]) return 0;
|
|
||||||
if (line_copy[0] == '#') return 0;
|
|
||||||
|
|
||||||
bsh_token_t toks[MAX_TOKENS];
|
|
||||||
int tcount = tokenize_line(line_copy, toks, MAX_TOKENS);
|
|
||||||
if (tcount < 0) return 1;
|
|
||||||
if (tcount == 0 || toks[0].type == TOK_END) return 0;
|
|
||||||
|
|
||||||
int idx = 0;
|
|
||||||
int status = 0;
|
|
||||||
bool want_exit = false;
|
|
||||||
|
|
||||||
while (toks[idx].type != TOK_END) {
|
|
||||||
if (toks[idx].type == TOK_SEMI || toks[idx].type == TOK_AMP) {
|
|
||||||
print_syntax_error("unexpected separator");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int end_idx = idx;
|
|
||||||
if (!parse_conditional_end_index(toks, idx, &end_idx)) return 1;
|
|
||||||
|
|
||||||
bool background = false;
|
|
||||||
if (toks[end_idx].type == TOK_AMP) background = true;
|
|
||||||
|
|
||||||
status = execute_conditional_range(toks, idx, end_idx, background, &want_exit);
|
|
||||||
if (want_exit) return 2;
|
|
||||||
|
|
||||||
idx = end_idx;
|
|
||||||
if (toks[idx].type == TOK_SEMI || toks[idx].type == TOK_AMP) {
|
|
||||||
idx++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (toks[idx].type != TOK_END) {
|
|
||||||
print_syntax_error("unexpected token after command list");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool run_script(const char *path) {
|
static bool run_script(const char *path) {
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,6 @@ 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;
|
||||||
|
|
||||||
|
|
@ -61,10 +60,6 @@ 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) {
|
||||||
|
|
@ -78,7 +73,6 @@ 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];
|
||||||
}
|
}
|
||||||
|
|
@ -280,7 +274,6 @@ __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;
|
||||||
|
|
||||||
|
|
@ -307,7 +300,7 @@ __attribute__((weak)) int close(int fd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (h->type == HANDLE_KERNEL_FD) {
|
if (h->type == HANDLE_KERNEL_FD) {
|
||||||
if (h->owns_kernel_fd) {
|
if (h->kernel_fd >= 3) {
|
||||||
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) {
|
||||||
|
|
@ -391,13 +384,10 @@ __attribute__((weak)) ssize_t write(int fd, const void *buf, size_t count) {
|
||||||
return (ssize_t)n;
|
return (ssize_t)n;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_b_is_stdio_handle(h)) {
|
if (h->kernel_fd <= 2) {
|
||||||
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) {
|
||||||
|
|
@ -452,7 +442,7 @@ __attribute__((weak)) int isatty(int fd) {
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return (h->type == HANDLE_KERNEL_FD && _b_is_stdio_handle(h)) ? 1 : 0;
|
return (h->type == HANDLE_KERNEL_FD && h->kernel_fd <= 2) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((weak)) int fstat(int fd, struct stat *statbuf) {
|
__attribute__((weak)) int fstat(int fd, struct stat *statbuf) {
|
||||||
|
|
@ -481,38 +471,31 @@ __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();
|
||||||
|
|
||||||
src = _b_get_handle(oldfd);
|
h = _b_get_handle(oldfd);
|
||||||
if (!src) {
|
if (!h) {
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src->type != HANDLE_KERNEL_FD) {
|
if (h->type != HANDLE_KERNEL_FD) {
|
||||||
errno = ENOTSUP;
|
errno = ENOTSUP;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
newkfd = sys_dup(src->kernel_fd);
|
newkfd = sys_dup(h->kernel_fd);
|
||||||
if (newkfd < 0) {
|
if (newkfd < 0) {
|
||||||
if (_b_is_stdio_handle(src)) {
|
|
||||||
newkfd = src->kernel_fd;
|
|
||||||
} else {
|
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
newfd = _b_alloc_fd_from(0);
|
newfd = _b_alloc_fd_from(0);
|
||||||
if (newfd < 0) {
|
if (newfd < 0) {
|
||||||
if (newkfd >= 3) {
|
|
||||||
sys_close(newkfd);
|
sys_close(newkfd);
|
||||||
}
|
errno = EBUSY;
|
||||||
errno = EBADF;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -527,20 +510,19 @@ __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 *src;
|
fd_handle_t *h;
|
||||||
fd_handle_t *nh;
|
fd_handle_t *nh;
|
||||||
int kfd_res;
|
int newkfd;
|
||||||
_b_fd_init();
|
_b_fd_init();
|
||||||
|
|
||||||
src = _b_get_handle(oldfd);
|
h = _b_get_handle(oldfd);
|
||||||
if (!src || newfd < 0 || newfd >= POSIX_MAX_FDS) {
|
if (!h || newfd < 0 || newfd >= POSIX_MAX_FDS) {
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -549,48 +531,36 @@ __attribute__((weak)) int dup2(int oldfd, int newfd) {
|
||||||
return newfd;
|
return newfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src->type != HANDLE_KERNEL_FD) {
|
if (h->type != HANDLE_KERNEL_FD) {
|
||||||
errno = ENOTSUP;
|
errno = ENOTSUP;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force kernel to update its FD table for the new slot
|
if (g_fd_table[newfd]) {
|
||||||
kfd_res = sys_dup2(src->kernel_fd, newfd);
|
if (close(newfd) != 0) {
|
||||||
if (kfd_res < 0) {
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newkfd = sys_dup(h->kernel_fd);
|
||||||
|
if (newkfd < 0) {
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If newfd was already open in libc, we need to replace its handle
|
|
||||||
if (g_fd_table[newfd] && !_b_is_stdio_handle(g_fd_table[newfd])) {
|
|
||||||
close(newfd);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If it's a stdio handle, we update it in place
|
|
||||||
if (newfd >= 0 && newfd <= 2) {
|
|
||||||
nh = &g_stdio_handles[newfd];
|
|
||||||
nh->type = HANDLE_KERNEL_FD;
|
|
||||||
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));
|
nh = (fd_handle_t *)malloc(sizeof(fd_handle_t));
|
||||||
if (!nh) {
|
if (!nh) {
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
nh->type = HANDLE_KERNEL_FD;
|
nh->type = HANDLE_KERNEL_FD;
|
||||||
nh->refcount = 1;
|
nh->refcount = 1;
|
||||||
nh->flags = src->flags;
|
nh->flags = h->flags;
|
||||||
nh->kernel_fd = newfd;
|
nh->kernel_fd = newkfd;
|
||||||
nh->owns_kernel_fd = 1;
|
|
||||||
nh->pipe = NULL;
|
nh->pipe = NULL;
|
||||||
g_fd_table[newfd] = nh;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
g_fd_table[newfd] = nh;
|
||||||
return newfd;
|
return newfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue