From 858e5dcaff090c14b90f17ebac166ca03062473a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Fri, 28 Mar 2025 13:14:10 +0100 Subject: [PATCH 1/8] fix: remove line creating a second ext4 partition --- filesystem/create_img.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/filesystem/create_img.sh b/filesystem/create_img.sh index 6b6e2e984..b6ad4c577 100755 --- a/filesystem/create_img.sh +++ b/filesystem/create_img.sh @@ -39,7 +39,6 @@ if [[ "$devname" = *[0-9] ]]; then fi sudo mkfs.fat -F32 -v /dev/"$devname"1 -sudo mkfs.ext4 /dev/"$devname"2 if [ "$1" == "virt32" -o "$1" == "virt64" ]; then sudo losetup -D From f6df329167f00a661c21b8a96c12f95501f5d47f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Fri, 28 Mar 2025 13:14:54 +0100 Subject: [PATCH 2/8] chore: ignore all sdcard images --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index f5e699feb..2633d745d 100755 --- a/.gitignore +++ b/.gitignore @@ -57,7 +57,7 @@ so3/so3 so3/so3.bin usr/lib/libc/include/asm rootfs/rootfs.fat -filesystem/sdcard.img.virt32 +filesystem/sdcard.img.* so3/scripts/basic/fixdep so3/scripts/dtc/dtc so3/scripts/kconfig/conf From 8eda0e78bf241f0188d344a7e4306674bb259603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Fri, 28 Mar 2025 13:15:37 +0100 Subject: [PATCH 3/8] feat: so3 init program --- usr/src/CMakeLists.txt | 2 + usr/src/init.c | 265 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 267 insertions(+) create mode 100644 usr/src/init.c diff --git a/usr/src/CMakeLists.txt b/usr/src/CMakeLists.txt index 1ede938d1..5731613e3 100644 --- a/usr/src/CMakeLists.txt +++ b/usr/src/CMakeLists.txt @@ -1,4 +1,5 @@ +add_executable(init.elf init.c) add_executable(sh.elf sh.c) add_executable(ls.elf ls.c) add_executable(more.elf more.c) @@ -9,6 +10,7 @@ add_executable(lvgl_demo.elf lvgl_demo.c) add_executable(lvgl_perf.elf lvgl_perf.c) add_executable(lvgl_benchmark.elf lvgl_benchmark.c) +target_link_libraries(init.elf c) target_link_libraries(sh.elf c) target_link_libraries(ls.elf c) target_link_libraries(more.elf c) diff --git a/usr/src/init.c b/usr/src/init.c new file mode 100644 index 000000000..3c9724792 --- /dev/null +++ b/usr/src/init.c @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2025 André Costa + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +/* + * Simple Init Program for SO3 + * ---------------------------- + * This program serves as a minimal init system for SO3, capable of reading and + * executing commands from a configuration file. + * + * Supported Commands: + * ------------------- + * - exit : Terminates the init process. + * - shell : Launches the shell (`sh.elf`). + * - echo : Prints arguments to stdout. + * - run : Executes an ELF binary specified by , along with any + * additional arguments provided. + * + * Command Execution: + * ------------------ + * Commands are read from a file and executed sequentially. + * The "run" command forks a new process, executes the specified ELF binary, + * and waits for its completion before proceeding to the next command. + * By default, the program executes the shell program when it's done, you can + * change this behaviour with an `exit` command at the end of the file. + * + * This init system simplifies scripting in SO3 by allowing easy modifications + * through a simple text-based configuration. + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define INPUT_COMMAND_FILE "init_commands.txt" +#define ARGS_MAX 16 +#define MAX_COMMAND_LEN 512 + +int fd = -1; +static void close_file(void); +static void start_shell(void); + +void close_file(void) +{ + if (fd >= 0) { + close(fd); + } + fd = -1; +} +/* + * Executes the shell + * This function replaces the current process with the shell executable. + * If execv fails, the process will terminate. + * + */ +void start_shell(void) +{ + execv("sh.elf", NULL); + printf("Error starting shell\n"); + exit(1); +} + +/** + * Detect if its a escape sequence + */ +int is_escape_sequence(const char *str) +{ + return str[0] == '\x1b' && str[1] == '['; +} + +/** + * Escape arrow key sequence to avoid interpret them + */ +void escape_arrow_key(char *buffer, int size) +{ + int i, j; + char *new_buff = calloc(size, sizeof(char)); + i = j = 0; + while (i < size) { + if (is_escape_sequence(&buffer[i])) { + i += 3; + } else { + new_buff[j++] = buffer[i++]; + } + } + memcpy(buffer, new_buff, size); + free(new_buff); +} + +/* + * Processes a command which must be a NULL-terminated string + * + * Returns -1 on error + */ +int process_cmd(const char *command) +{ + if (command == NULL) { + printf("Command is null\n"); + return -1; + } + + if (strlen(command) >= MAX_COMMAND_LEN) { + printf("Command is too big. Ignoring it\n"); + return -1; + } + + char buffer[MAX_COMMAND_LEN]; + char *args[ARGS_MAX]; + size_t argc = 0; + strcpy(buffer, command); + + char *token = strtok(buffer, " "); + while (token != NULL) { + if (argc >= ARGS_MAX - 1) { + printf("Too many command arguments found. Ignoring the command\n"); + return -1; + } + args[argc++] = token; + token = strtok(NULL, " "); + } + + args[argc] = NULL; + + if (argc < 1) { + printf("Invalid command format: %s\n", command); + return -1; + } + + if (strcmp(args[0], "exit") == 0) { + close_file(); + exit(0); + } else if (strcmp(args[0], "shell") == 0) { + start_shell(); + printf("Failed to launch shell\n"); + return -1; + } else if (strcmp(args[0], "echo") == 0) { + for (size_t i = 1; i < argc; ++i) { + printf("%s ", args[i]); + } + printf("\n"); + return 0; + } else if (strcmp(args[0], "run") == 0) { + if (argc < 2) { + printf("Missing filename for 'run' command\n"); + return -1; + } + + pid_t pid = fork(); + if (pid < 0) { + printf("Fork failed\n"); + return -1; + } else if (pid == 0) { + execv(args[1], &args[1]); + printf("Execv failed\n"); + exit(1); + } else { + int status; + waitpid(pid, &status, 0); + return WEXITSTATUS(status); + } + } else { + printf("Unknown command: %s\n", args[0]); + return -1; + } + + return 0; +} + +/* + * Ignore the SIGINT signal unless + */ +void sigint_handler(int sig) +{ + (void)sig; +} +/* + * Processes the file given by `fd` + * It's the caller's responsability to close `fd` + * + * Returns -1 on error and 0 on success + */ +int process_file(int fd) +{ +#define LINE_LEN MAX_COMMAND_LEN + 1 + + char buffer[LINE_LEN]; + char line[LINE_LEN]; + int line_index = 0; + ssize_t bytes_read; + int i; + + while ((bytes_read = read(fd, buffer, sizeof(buffer))) > 0) { + for (i = 0; i < bytes_read; i++) { + if (buffer[i] == '\n') { + line[line_index] = '\0'; + if (line_index > 0) { + process_cmd(line); + } + line_index = 0; + } else if (line_index >= LINE_LEN) { + printf("Invalid Command file, command is too big\n"); + return -1; + } else { + line[line_index++] = buffer[i]; + } + } + } + + // Handle the last command if the file doesn't end with a newline + if (line_index > 0) { + line[line_index] = '\0'; + process_cmd(line); + } + return 0; +} + +/* + * Main entry point of the init application. + */ +int main(int argc, char *argv[]) +{ + struct sigaction sa; + printf("Now running So3 usr init\n"); + fd = open(INPUT_COMMAND_FILE, O_RDONLY); + /* By default, we start the shell process */ + if (fd < 0) { + start_shell(); + return EXIT_FAILURE; + } + + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_handler = sigint_handler; + sigaction(SIGINT, &sa, NULL); + + process_file(fd); + close_file(); + + start_shell(); + /* Unreachable */ + return EXIT_FAILURE; +} From b736a9a58be6ef3a350e3683ddd3df0704749781 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Fri, 28 Mar 2025 13:15:51 +0100 Subject: [PATCH 4/8] chore: add sample init commands --- usr/out/init_commands.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 usr/out/init_commands.txt diff --git a/usr/out/init_commands.txt b/usr/out/init_commands.txt new file mode 100644 index 000000000..93be3dd1e --- /dev/null +++ b/usr/out/init_commands.txt @@ -0,0 +1,2 @@ +echo SO3 Init Program :) +shell From e7956bb2089ae343df8dc0501ec31d7c6c893e72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Fri, 28 Mar 2025 13:17:12 +0100 Subject: [PATCH 5/8] feat: set default init program to init.elf --- so3/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/so3/Kconfig b/so3/Kconfig index 80419745e..e614ba657 100644 --- a/so3/Kconfig +++ b/so3/Kconfig @@ -23,7 +23,7 @@ config AVZ config USER_INIT_PROGRAM string "Specifies the initial user-space ELF executable to be started at system boot" - default "sh.elf" + default "init.elf" if !AVZ config SOO From d49478645729a52d416337c92be51f29c3784e1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Fri, 28 Mar 2025 13:32:39 +0100 Subject: [PATCH 6/8] refactor: remove unused functions --- usr/src/init.c | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/usr/src/init.c b/usr/src/init.c index 3c9724792..d1061e430 100644 --- a/usr/src/init.c +++ b/usr/src/init.c @@ -84,33 +84,6 @@ void start_shell(void) exit(1); } -/** - * Detect if its a escape sequence - */ -int is_escape_sequence(const char *str) -{ - return str[0] == '\x1b' && str[1] == '['; -} - -/** - * Escape arrow key sequence to avoid interpret them - */ -void escape_arrow_key(char *buffer, int size) -{ - int i, j; - char *new_buff = calloc(size, sizeof(char)); - i = j = 0; - while (i < size) { - if (is_escape_sequence(&buffer[i])) { - i += 3; - } else { - new_buff[j++] = buffer[i++]; - } - } - memcpy(buffer, new_buff, size); - free(new_buff); -} - /* * Processes a command which must be a NULL-terminated string * From db64e9395e1727a69e65cbd9a6dbce75afaed263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Fri, 28 Mar 2025 13:33:24 +0100 Subject: [PATCH 7/8] refactor: declare static functions --- usr/src/init.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/usr/src/init.c b/usr/src/init.c index d1061e430..68bc2c1d8 100644 --- a/usr/src/init.c +++ b/usr/src/init.c @@ -61,8 +61,12 @@ #define MAX_COMMAND_LEN 512 int fd = -1; + static void close_file(void); static void start_shell(void); +static int process_cmd(const char *command); +static void sigint_handler(int sig); +static int process_file(int fd); void close_file(void) { From 0c278b41f76f8602a9d1887fe91e5ab8a2af16ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Fri, 28 Mar 2025 13:33:43 +0100 Subject: [PATCH 8/8] refactor: define variables on top of function --- usr/src/init.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/usr/src/init.c b/usr/src/init.c index 68bc2c1d8..2e9118128 100644 --- a/usr/src/init.c +++ b/usr/src/init.c @@ -95,6 +95,12 @@ void start_shell(void) */ int process_cmd(const char *command) { + char buffer[MAX_COMMAND_LEN]; + char *args[ARGS_MAX]; + char *token; + size_t argc = 0; + + strcpy(buffer, command); if (command == NULL) { printf("Command is null\n"); return -1; @@ -105,12 +111,7 @@ int process_cmd(const char *command) return -1; } - char buffer[MAX_COMMAND_LEN]; - char *args[ARGS_MAX]; - size_t argc = 0; - strcpy(buffer, command); - - char *token = strtok(buffer, " "); + token = strtok(buffer, " "); while (token != NULL) { if (argc >= ARGS_MAX - 1) { printf("Too many command arguments found. Ignoring the command\n");