From 643b26cfb287c928841f31949ce370a536fa7785 Mon Sep 17 00:00:00 2001 From: Leonmmcoset Date: Thu, 16 Apr 2026 19:29:42 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BD=BB=E5=BA=95=E6=8B=86=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 5 +- cleonos/c/apps/ansi_main.c | 55 +- cleonos/c/apps/ansitest_main.c | 175 +- cleonos/c/apps/append_main.c | 91 +- cleonos/c/apps/cat_main.c | 106 +- cleonos/c/apps/cd_main.c | 68 +- cleonos/c/apps/clear_main.c | 51 +- cleonos/c/apps/cmd_runtime.c | 588 +++++++ cleonos/c/apps/cmd_runtime.h | 98 ++ cleonos/c/apps/cp_main.c | 120 +- cleonos/c/apps/dmesg_main.c | 81 +- cleonos/c/apps/exec_main.c | 76 +- cleonos/c/apps/exit_main.c | 67 +- cleonos/c/apps/fastfetch_main.c | 212 ++- cleonos/c/apps/fsstat_main.c | 57 +- cleonos/c/apps/grep_main.c | 247 ++- cleonos/c/apps/help_main.c | 83 +- cleonos/c/apps/kbdstat_main.c | 56 +- cleonos/c/apps/ls_main.c | 337 +++- cleonos/c/apps/memstat_main.c | 55 +- cleonos/c/apps/mkdir_main.c | 72 +- cleonos/c/apps/mv_main.c | 129 +- cleonos/c/apps/pid_main.c | 51 +- cleonos/c/apps/pwd_main.c | 51 +- cleonos/c/apps/restart_main.c | 52 +- cleonos/c/apps/rm_main.c | 72 +- cleonos/c/apps/shell/cmd/ansi.inc | 8 - cleonos/c/apps/shell/cmd/ansitest.inc | 41 - .../c/apps/shell/cmd/ansitest_emit_bg256.inc | 43 - .../c/apps/shell/cmd/ansitest_u64_to_dec.inc | 36 - cleonos/c/apps/shell/cmd/append.inc | 44 - cleonos/c/apps/shell/cmd/cat.inc | 59 - cleonos/c/apps/shell/cmd/cd.inc | 21 - cleonos/c/apps/shell/cmd/clear.inc | 4 - cleonos/c/apps/shell/cmd/copy_file.inc | 43 - cleonos/c/apps/shell/cmd/cp.inc | 29 - cleonos/c/apps/shell/cmd/dmesg.inc | 34 - cleonos/c/apps/shell/cmd/exec.inc | 29 - cleonos/c/apps/shell/cmd/exit.inc | 20 - cleonos/c/apps/shell/cmd/fastfetch.inc | 56 - .../c/apps/shell/cmd/fastfetch_print_logo.inc | 25 - .../shell/cmd/fastfetch_print_palette.inc | 14 - .../c/apps/shell/cmd/fastfetch_print_text.inc | 4 - .../c/apps/shell/cmd/fastfetch_print_u64.inc | 5 - .../c/apps/shell/cmd/fastfetch_u64_to_dec.inc | 34 - .../c/apps/shell/cmd/fastfetch_write_key.inc | 11 - .../shell/cmd/fastfetch_write_u64_dec.inc | 10 - cleonos/c/apps/shell/cmd/fsstat.inc | 10 - cleonos/c/apps/shell/cmd/grep.inc | 109 -- .../c/apps/shell/cmd/grep_emit_matches.inc | 41 - .../apps/shell/cmd/grep_line_has_pattern.inc | 29 - .../c/apps/shell/cmd/grep_write_u64_dec.inc | 19 - cleonos/c/apps/shell/cmd/help.inc | 36 - cleonos/c/apps/shell/cmd/kbdstat.inc | 9 - cleonos/c/apps/shell/cmd/ls.inc | 32 - cleonos/c/apps/shell/cmd/ls_basename.inc | 18 - cleonos/c/apps/shell/cmd/ls_dir.inc | 79 - cleonos/c/apps/shell/cmd/ls_is_dot_entry.inc | 15 - cleonos/c/apps/shell/cmd/ls_join_path.inc | 43 - cleonos/c/apps/shell/cmd/ls_parse_args.inc | 70 - cleonos/c/apps/shell/cmd/ls_print_one.inc | 27 - cleonos/c/apps/shell/cmd/memstat.inc | 8 - cleonos/c/apps/shell/cmd/mkdir.inc | 25 - cleonos/c/apps/shell/cmd/mv.inc | 38 - cleonos/c/apps/shell/cmd/not_supported.inc | 6 - cleonos/c/apps/shell/cmd/pid.inc | 4 - cleonos/c/apps/shell/cmd/pwd.inc | 4 - cleonos/c/apps/shell/cmd/restart.inc | 5 - cleonos/c/apps/shell/cmd/rm.inc | 25 - cleonos/c/apps/shell/cmd/shstat.inc | 10 - cleonos/c/apps/shell/cmd/shutdown.inc | 5 - cleonos/c/apps/shell/cmd/sleep.inc | 18 - cleonos/c/apps/shell/cmd/spawn.inc | 25 - cleonos/c/apps/shell/cmd/stats.inc | 9 - cleonos/c/apps/shell/cmd/taskstat.inc | 8 - cleonos/c/apps/shell/cmd/touch.inc | 26 - cleonos/c/apps/shell/cmd/tty.inc | 33 - cleonos/c/apps/shell/cmd/userstat.inc | 13 - cleonos/c/apps/shell/cmd/wait.inc | 31 - cleonos/c/apps/shell/cmd/write.inc | 44 - cleonos/c/apps/shell/cmd/yield.inc | 4 - cleonos/c/apps/shell/shell_cmd.c | 1506 ++++++++++++++++- cleonos/c/apps/shell/shell_external.c | 111 -- cleonos/c/apps/shell/shell_internal.h | 2 - cleonos/c/apps/shstat_main.c | 57 +- cleonos/c/apps/shutdown_main.c | 52 +- cleonos/c/apps/sleep_main.c | 65 +- cleonos/c/apps/spawn_main.c | 72 +- cleonos/c/apps/stats_main.c | 120 +- cleonos/c/apps/taskstat_main.c | 55 +- cleonos/c/apps/touch_main.c | 73 +- cleonos/c/apps/tty_main.c | 80 +- cleonos/c/apps/userstat_main.c | 60 +- cleonos/c/apps/wait_main.c | 78 +- cleonos/c/apps/write_main.c | 91 +- cleonos/c/apps/yield_main.c | 51 +- 96 files changed, 5239 insertions(+), 1737 deletions(-) create mode 100644 cleonos/c/apps/cmd_runtime.c create mode 100644 cleonos/c/apps/cmd_runtime.h delete mode 100644 cleonos/c/apps/shell/cmd/ansi.inc delete mode 100644 cleonos/c/apps/shell/cmd/ansitest.inc delete mode 100644 cleonos/c/apps/shell/cmd/ansitest_emit_bg256.inc delete mode 100644 cleonos/c/apps/shell/cmd/ansitest_u64_to_dec.inc delete mode 100644 cleonos/c/apps/shell/cmd/append.inc delete mode 100644 cleonos/c/apps/shell/cmd/cat.inc delete mode 100644 cleonos/c/apps/shell/cmd/cd.inc delete mode 100644 cleonos/c/apps/shell/cmd/clear.inc delete mode 100644 cleonos/c/apps/shell/cmd/copy_file.inc delete mode 100644 cleonos/c/apps/shell/cmd/cp.inc delete mode 100644 cleonos/c/apps/shell/cmd/dmesg.inc delete mode 100644 cleonos/c/apps/shell/cmd/exec.inc delete mode 100644 cleonos/c/apps/shell/cmd/exit.inc delete mode 100644 cleonos/c/apps/shell/cmd/fastfetch.inc delete mode 100644 cleonos/c/apps/shell/cmd/fastfetch_print_logo.inc delete mode 100644 cleonos/c/apps/shell/cmd/fastfetch_print_palette.inc delete mode 100644 cleonos/c/apps/shell/cmd/fastfetch_print_text.inc delete mode 100644 cleonos/c/apps/shell/cmd/fastfetch_print_u64.inc delete mode 100644 cleonos/c/apps/shell/cmd/fastfetch_u64_to_dec.inc delete mode 100644 cleonos/c/apps/shell/cmd/fastfetch_write_key.inc delete mode 100644 cleonos/c/apps/shell/cmd/fastfetch_write_u64_dec.inc delete mode 100644 cleonos/c/apps/shell/cmd/fsstat.inc delete mode 100644 cleonos/c/apps/shell/cmd/grep.inc delete mode 100644 cleonos/c/apps/shell/cmd/grep_emit_matches.inc delete mode 100644 cleonos/c/apps/shell/cmd/grep_line_has_pattern.inc delete mode 100644 cleonos/c/apps/shell/cmd/grep_write_u64_dec.inc delete mode 100644 cleonos/c/apps/shell/cmd/help.inc delete mode 100644 cleonos/c/apps/shell/cmd/kbdstat.inc delete mode 100644 cleonos/c/apps/shell/cmd/ls.inc delete mode 100644 cleonos/c/apps/shell/cmd/ls_basename.inc delete mode 100644 cleonos/c/apps/shell/cmd/ls_dir.inc delete mode 100644 cleonos/c/apps/shell/cmd/ls_is_dot_entry.inc delete mode 100644 cleonos/c/apps/shell/cmd/ls_join_path.inc delete mode 100644 cleonos/c/apps/shell/cmd/ls_parse_args.inc delete mode 100644 cleonos/c/apps/shell/cmd/ls_print_one.inc delete mode 100644 cleonos/c/apps/shell/cmd/memstat.inc delete mode 100644 cleonos/c/apps/shell/cmd/mkdir.inc delete mode 100644 cleonos/c/apps/shell/cmd/mv.inc delete mode 100644 cleonos/c/apps/shell/cmd/not_supported.inc delete mode 100644 cleonos/c/apps/shell/cmd/pid.inc delete mode 100644 cleonos/c/apps/shell/cmd/pwd.inc delete mode 100644 cleonos/c/apps/shell/cmd/restart.inc delete mode 100644 cleonos/c/apps/shell/cmd/rm.inc delete mode 100644 cleonos/c/apps/shell/cmd/shstat.inc delete mode 100644 cleonos/c/apps/shell/cmd/shutdown.inc delete mode 100644 cleonos/c/apps/shell/cmd/sleep.inc delete mode 100644 cleonos/c/apps/shell/cmd/spawn.inc delete mode 100644 cleonos/c/apps/shell/cmd/stats.inc delete mode 100644 cleonos/c/apps/shell/cmd/taskstat.inc delete mode 100644 cleonos/c/apps/shell/cmd/touch.inc delete mode 100644 cleonos/c/apps/shell/cmd/tty.inc delete mode 100644 cleonos/c/apps/shell/cmd/userstat.inc delete mode 100644 cleonos/c/apps/shell/cmd/wait.inc delete mode 100644 cleonos/c/apps/shell/cmd/write.inc delete mode 100644 cleonos/c/apps/shell/cmd/yield.inc diff --git a/CMakeLists.txt b/CMakeLists.txt index c6f69dd..6cf33a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -392,10 +392,7 @@ foreach(SRC IN LISTS USER_APP_MAIN_SOURCES) list(FIND USER_SHELL_COMMAND_APPS "${_app_name}" _shell_cmd_idx) if(NOT _shell_cmd_idx EQUAL -1) - file(GLOB _shell_cmd_shared_abs CONFIGURE_DEPENDS - "${CMAKE_SOURCE_DIR}/cleonos/c/apps/shell/*.c" - ) - list(APPEND _app_specific_abs ${_shell_cmd_shared_abs}) + list(APPEND _app_specific_abs "${CMAKE_SOURCE_DIR}/cleonos/c/apps/cmd_runtime.c") endif() foreach(_extra_abs IN LISTS _app_specific_abs) file(RELATIVE_PATH _extra_rel "${CMAKE_SOURCE_DIR}" "${_extra_abs}") diff --git a/cleonos/c/apps/ansi_main.c b/cleonos/c/apps/ansi_main.c index e73cfba..ff4bdd6 100644 --- a/cleonos/c/apps/ansi_main.c +++ b/cleonos/c/apps/ansi_main.c @@ -1,6 +1,53 @@ -#include "shell/shell_internal.h" - -int cleonos_app_main(void) { - return ush_command_program_main("ansi"); +#include "cmd_runtime.h" +static int ush_cmd_ansi(void) { + ush_writeln("\x1B[1;36mansi color demo\x1B[0m"); + ush_writeln(" \x1B[30mblack\x1B[0m \x1B[31mred\x1B[0m \x1B[32mgreen\x1B[0m \x1B[33myellow\x1B[0m"); + ush_writeln(" \x1B[34mblue\x1B[0m \x1B[35mmagenta\x1B[0m \x1B[36mcyan\x1B[0m \x1B[37mwhite\x1B[0m"); + ush_writeln(" \x1B[90mbright-black\x1B[0m \x1B[91mbright-red\x1B[0m \x1B[92mbright-green\x1B[0m \x1B[93mbright-yellow\x1B[0m"); + ush_writeln(" \x1B[94mbright-blue\x1B[0m \x1B[95mbright-magenta\x1B[0m \x1B[96mbright-cyan\x1B[0m \x1B[97mbright-white\x1B[0m"); + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "ansi") != 0) { + has_context = 1; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_ansi(); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/ansitest_main.c b/cleonos/c/apps/ansitest_main.c index 8084078..c2b3507 100644 --- a/cleonos/c/apps/ansitest_main.c +++ b/cleonos/c/apps/ansitest_main.c @@ -1,5 +1,176 @@ -#include "shell/shell_internal.h" +#include "cmd_runtime.h" +static int ush_cmd_ansi(void) { + ush_writeln("\x1B[1;36mansi color demo\x1B[0m"); + ush_writeln(" \x1B[30mblack\x1B[0m \x1B[31mred\x1B[0m \x1B[32mgreen\x1B[0m \x1B[33myellow\x1B[0m"); + ush_writeln(" \x1B[34mblue\x1B[0m \x1B[35mmagenta\x1B[0m \x1B[36mcyan\x1B[0m \x1B[37mwhite\x1B[0m"); + ush_writeln(" \x1B[90mbright-black\x1B[0m \x1B[91mbright-red\x1B[0m \x1B[92mbright-green\x1B[0m \x1B[93mbright-yellow\x1B[0m"); + ush_writeln(" \x1B[94mbright-blue\x1B[0m \x1B[95mbright-magenta\x1B[0m \x1B[96mbright-cyan\x1B[0m \x1B[97mbright-white\x1B[0m"); + return 1; +} + +static u64 ush_ansitest_u64_to_dec(char *out, u64 out_size, u64 value) { + char rev[10]; + u64 digits = 0ULL; + u64 i; + + if (out == (char *)0 || out_size == 0ULL) { + return 0ULL; + } + + if (value == 0U) { + if (out_size < 2ULL) { + return 0ULL; + } + + out[0] = '0'; + out[1] = '\0'; + return 1ULL; + } + + while (value > 0U && digits < (u64)sizeof(rev)) { + rev[digits++] = (char)('0' + (value % 10U)); + value /= 10U; + } + + if (digits + 1ULL > out_size) { + out[0] = '\0'; + return 0ULL; + } + + for (i = 0ULL; i < digits; i++) { + out[i] = rev[digits - 1ULL - i]; + } + + out[digits] = '\0'; + return digits; +} + +static void ush_ansitest_emit_bg256(u64 index) { + char num[4]; + char seq[24]; + u64 digits; + u64 p = 0ULL; + u64 i; + + if (index > 255U) { + index = 255U; + } + + digits = ush_ansitest_u64_to_dec(num, (u64)sizeof(num), index); + if (digits == 0ULL) { + return; + } + + seq[p++] = '\x1B'; + seq[p++] = '['; + seq[p++] = '4'; + seq[p++] = '8'; + seq[p++] = ';'; + seq[p++] = '5'; + seq[p++] = ';'; + + for (i = 0ULL; i < digits && p + 1ULL < (u64)sizeof(seq); i++) { + seq[p++] = num[i]; + } + + if (p + 7ULL >= (u64)sizeof(seq)) { + return; + } + + seq[p++] = 'm'; + seq[p++] = ' '; + seq[p++] = ' '; + seq[p++] = '\x1B'; + seq[p++] = '['; + seq[p++] = '0'; + seq[p++] = 'm'; + seq[p] = '\0'; + + ush_write(seq); +} + +static int ush_cmd_ansitest(void) { + u64 i; + + ush_writeln("\x1B[1;96mANSI test suite\x1B[0m"); + ush_writeln("styles: \x1B[1mbold\x1B[0m \x1B[7minverse\x1B[0m \x1B[4munderline\x1B[0m"); + ush_writeln("16-color demo:"); + (void)ush_cmd_ansi(); + + ush_writeln("256-color palette (0..255):"); + for (i = 0ULL; i < 256ULL; i++) { + ush_ansitest_emit_bg256(i); + if ((i % 32ULL) == 31ULL) { + ush_write_char('\n'); + } + } + ush_write_char('\n'); + + ush_writeln("truecolor demo:"); + ush_writeln(" \x1B[38;2;255;64;64mRGB(255,64,64)\x1B[0m \x1B[38;2;64;255;64mRGB(64,255,64)\x1B[0m \x1B[38;2;64;128;255mRGB(64,128,255)\x1B[0m"); + + ush_writeln("cursor control demo:"); + ush_write(" 0123456789"); + ush_write("\x1B[5D"); + ush_write("\x1B[93m\x1B[0m"); + ush_write_char('\n'); + + ush_write(" save"); + ush_write("\x1B[s"); + ush_write("...."); + ush_write("\x1B[u"); + ush_write("\x1B[92m\x1B[0m"); + ush_write_char('\n'); + + ush_writeln("erase-line demo:"); + ush_write(" left|right-to-clear"); + ush_write("\x1B[14D\x1B[K"); + ush_write_char('\n'); + + ush_writeln("ansitest done"); + return 1; +} + int cleonos_app_main(void) { - return ush_command_program_main("ansitest"); + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "ansitest") != 0) { + has_context = 1; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_ansitest(); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } + diff --git a/cleonos/c/apps/append_main.c b/cleonos/c/apps/append_main.c index 0136af7..614e13d 100644 --- a/cleonos/c/apps/append_main.c +++ b/cleonos/c/apps/append_main.c @@ -1,6 +1,91 @@ -#include "shell/shell_internal.h" +#include "cmd_runtime.h" +static int ush_cmd_append(const ush_state *sh, const char *arg) { + char path_arg[USH_PATH_MAX]; + char abs_path[USH_PATH_MAX]; + const char *payload = (const char *)0; + u64 payload_len; -int cleonos_app_main(void) { - return ush_command_program_main("append"); + if (arg == (const char *)0 || arg[0] == '\0') { + ush_writeln("append: usage append "); + return 0; + } + + if (ush_split_first_and_rest(arg, path_arg, (u64)sizeof(path_arg), &payload) == 0) { + ush_writeln("append: usage append "); + return 0; + } + + if (ush_resolve_path(sh, path_arg, abs_path, (u64)sizeof(abs_path)) == 0) { + ush_writeln("append: invalid path"); + return 0; + } + + if (ush_path_is_under_temp(abs_path) == 0) { + ush_writeln("append: target must be under /temp"); + return 0; + } + + if (payload == (const char *)0 || payload[0] == '\0') { + if (ush_pipeline_stdin_text == (const char *)0) { + ush_writeln("append: usage append "); + return 0; + } + payload = ush_pipeline_stdin_text; + payload_len = ush_pipeline_stdin_len; + } else { + payload_len = ush_strlen(payload); + } + + if (cleonos_sys_fs_append(abs_path, payload, payload_len) == 0ULL) { + ush_writeln("append: failed"); + return 0; + } + + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + const char *arg = ""; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "append") != 0) { + has_context = 1; + arg = ctx.arg; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_append(&sh, arg); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/cat_main.c b/cleonos/c/apps/cat_main.c index 38f6153..3159ce7 100644 --- a/cleonos/c/apps/cat_main.c +++ b/cleonos/c/apps/cat_main.c @@ -1,6 +1,106 @@ -#include "shell/shell_internal.h" +#include "cmd_runtime.h" +static int ush_cmd_cat(const ush_state *sh, const char *arg) { + char path[USH_PATH_MAX]; + char buf[USH_CAT_MAX + 1ULL]; + u64 size; + u64 req; + u64 got; -int cleonos_app_main(void) { - return ush_command_program_main("cat"); + if (arg == (const char *)0 || arg[0] == '\0') { + if (ush_pipeline_stdin_text != (const char *)0 && ush_pipeline_stdin_len > 0ULL) { + ush_write(ush_pipeline_stdin_text); + return 1; + } + + ush_writeln("cat: file path required"); + return 0; + } + + if (ush_resolve_path(sh, arg, path, (u64)sizeof(path)) == 0) { + ush_writeln("cat: invalid path"); + return 0; + } + + if (cleonos_sys_fs_stat_type(path) != 1ULL) { + ush_writeln("cat: file not found"); + return 0; + } + + size = cleonos_sys_fs_stat_size(path); + + if (size == (u64)-1) { + ush_writeln("cat: failed to stat file"); + return 0; + } + + if (size == 0ULL) { + return 1; + } + + req = (size < USH_CAT_MAX) ? size : USH_CAT_MAX; + got = cleonos_sys_fs_read(path, buf, req); + + if (got == 0ULL) { + ush_writeln("cat: read failed"); + return 0; + } + + if (got > USH_CAT_MAX) { + got = USH_CAT_MAX; + } + + buf[got] = '\0'; + ush_writeln(buf); + + if (size > got) { + ush_writeln("[cat] output truncated"); + } + + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + const char *arg = ""; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "cat") != 0) { + has_context = 1; + arg = ctx.arg; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_cat(&sh, arg); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/cd_main.c b/cleonos/c/apps/cd_main.c index d3b2e6e..ce21f7a 100644 --- a/cleonos/c/apps/cd_main.c +++ b/cleonos/c/apps/cd_main.c @@ -1,6 +1,68 @@ -#include "shell/shell_internal.h" +#include "cmd_runtime.h" +static int ush_cmd_cd(ush_state *sh, const char *arg) { + const char *target = arg; + char path[USH_PATH_MAX]; -int cleonos_app_main(void) { - return ush_command_program_main("cd"); + if (target == (const char *)0 || target[0] == '\0') { + target = "/"; + } + + if (ush_resolve_path(sh, target, path, (u64)sizeof(path)) == 0) { + ush_writeln("cd: invalid path"); + return 0; + } + + if (cleonos_sys_fs_stat_type(path) != 2ULL) { + ush_writeln("cd: directory not found"); + return 0; + } + + ush_copy(sh->cwd, (u64)sizeof(sh->cwd), path); + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + const char *arg = ""; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "cd") != 0) { + has_context = 1; + arg = ctx.arg; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_cd(&sh, arg); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/clear_main.c b/cleonos/c/apps/clear_main.c index 01b4e42..82a4568 100644 --- a/cleonos/c/apps/clear_main.c +++ b/cleonos/c/apps/clear_main.c @@ -1,6 +1,49 @@ -#include "shell/shell_internal.h" - -int cleonos_app_main(void) { - return ush_command_program_main("clear"); +#include "cmd_runtime.h" +static int ush_cmd_clear(void) { + ush_write("\x1B[2J\x1B[H"); + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "clear") != 0) { + has_context = 1; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_clear(); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/cmd_runtime.c b/cleonos/c/apps/cmd_runtime.c new file mode 100644 index 0000000..869f77d --- /dev/null +++ b/cleonos/c/apps/cmd_runtime.c @@ -0,0 +1,588 @@ +#include "cmd_runtime.h" + +const char *ush_pipeline_stdin_text = (const char *)0; +u64 ush_pipeline_stdin_len = 0ULL; + +void ush_zero(void *ptr, u64 size) { + u64 i; + char *bytes = (char *)ptr; + + if (bytes == (char *)0) { + return; + } + + for (i = 0ULL; i < size; i++) { + bytes[i] = 0; + } +} + +void ush_init_state(ush_state *sh) { + if (sh == (ush_state *)0) { + return; + } + + ush_zero(sh, (u64)sizeof(*sh)); + ush_copy(sh->cwd, (u64)sizeof(sh->cwd), "/"); + sh->history_nav = -1; +} + +u64 ush_strlen(const char *str) { + u64 len = 0ULL; + + if (str == (const char *)0) { + return 0ULL; + } + + while (str[len] != '\0') { + len++; + } + + return len; +} + +int ush_streq(const char *left, const char *right) { + u64 i = 0ULL; + + if (left == (const char *)0 || right == (const char *)0) { + return 0; + } + + while (left[i] != '\0' && right[i] != '\0') { + if (left[i] != right[i]) { + return 0; + } + i++; + } + + return (left[i] == right[i]) ? 1 : 0; +} + +int ush_is_space(char ch) { + return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') ? 1 : 0; +} + +int ush_is_printable(char ch) { + return (ch >= 32 && ch <= 126) ? 1 : 0; +} + +int ush_has_suffix(const char *name, const char *suffix) { + u64 name_len; + u64 suffix_len; + u64 i; + + if (name == (const char *)0 || suffix == (const char *)0) { + return 0; + } + + name_len = ush_strlen(name); + suffix_len = ush_strlen(suffix); + + if (suffix_len > name_len) { + return 0; + } + + for (i = 0ULL; i < suffix_len; i++) { + if (name[name_len - suffix_len + i] != suffix[i]) { + return 0; + } + } + + return 1; +} + +int ush_contains_char(const char *text, char needle) { + u64 i = 0ULL; + + if (text == (const char *)0) { + return 0; + } + + while (text[i] != '\0') { + if (text[i] == needle) { + return 1; + } + i++; + } + + return 0; +} + +int ush_parse_u64_dec(const char *text, u64 *out_value) { + u64 value = 0ULL; + u64 i = 0ULL; + + if (text == (const char *)0 || out_value == (u64 *)0 || text[0] == '\0') { + return 0; + } + + while (text[i] != '\0') { + u64 digit; + + if (text[i] < '0' || text[i] > '9') { + return 0; + } + + digit = (u64)(text[i] - '0'); + + if (value > ((0xFFFFFFFFFFFFFFFFULL - digit) / 10ULL)) { + return 0; + } + + value = (value * 10ULL) + digit; + i++; + } + + *out_value = value; + return 1; +} + +void ush_copy(char *dst, u64 dst_size, const char *src) { + u64 i = 0ULL; + + if (dst == (char *)0 || src == (const char *)0 || dst_size == 0ULL) { + return; + } + + while (src[i] != '\0' && i + 1ULL < dst_size) { + dst[i] = src[i]; + i++; + } + + dst[i] = '\0'; +} + +void ush_trim_line(char *line) { + u64 start = 0ULL; + u64 i = 0ULL; + u64 len; + + if (line == (char *)0) { + return; + } + + while (line[start] != '\0' && ush_is_space(line[start]) != 0) { + start++; + } + + if (start > 0ULL) { + while (line[start + i] != '\0') { + line[i] = line[start + i]; + i++; + } + line[i] = '\0'; + } + + len = ush_strlen(line); + + while (len > 0ULL && ush_is_space(line[len - 1ULL]) != 0) { + line[len - 1ULL] = '\0'; + len--; + } +} + +void ush_parse_line(const char *line, char *out_cmd, u64 cmd_size, char *out_arg, u64 arg_size) { + u64 i = 0ULL; + u64 cmd_pos = 0ULL; + u64 arg_pos = 0ULL; + + if (line == (const char *)0 || out_cmd == (char *)0 || out_arg == (char *)0) { + return; + } + + out_cmd[0] = '\0'; + out_arg[0] = '\0'; + + while (line[i] != '\0' && ush_is_space(line[i]) != 0) { + i++; + } + + while (line[i] != '\0' && ush_is_space(line[i]) == 0) { + if (cmd_pos + 1ULL < cmd_size) { + out_cmd[cmd_pos++] = line[i]; + } + i++; + } + + out_cmd[cmd_pos] = '\0'; + + while (line[i] != '\0' && ush_is_space(line[i]) != 0) { + i++; + } + + while (line[i] != '\0') { + if (arg_pos + 1ULL < arg_size) { + out_arg[arg_pos++] = line[i]; + } + i++; + } + + out_arg[arg_pos] = '\0'; +} + +void ush_write(const char *text) { + u64 len; + + if (text == (const char *)0) { + return; + } + + len = ush_strlen(text); + + if (len == 0ULL) { + return; + } + + (void)cleonos_sys_tty_write(text, len); +} + +void ush_write_char(char ch) { + (void)cleonos_sys_tty_write_char(ch); +} + +void ush_writeln(const char *text) { + ush_write(text); + ush_write_char('\n'); +} + +void ush_write_hex_u64(u64 value) { + i64 nibble; + + ush_write("0X"); + + for (nibble = 15; nibble >= 0; nibble--) { + u64 current = (value >> (u64)(nibble * 4)) & 0x0FULL; + char out = (current < 10ULL) ? (char)('0' + current) : (char)('A' + (current - 10ULL)); + ush_write_char(out); + } +} + +void ush_print_kv_hex(const char *label, u64 value) { + ush_write(label); + ush_write(": "); + ush_write_hex_u64(value); + ush_write_char('\n'); +} + +static int ush_path_push_component(char *path, u64 path_size, u64 *io_len, const char *component, u64 comp_len) { + u64 i; + + if (path == (char *)0 || io_len == (u64 *)0 || component == (const char *)0 || comp_len == 0ULL) { + return 0; + } + + if (*io_len == 1ULL) { + if (*io_len + comp_len >= path_size) { + return 0; + } + + for (i = 0ULL; i < comp_len; i++) { + path[1ULL + i] = component[i]; + } + + *io_len = 1ULL + comp_len; + path[*io_len] = '\0'; + return 1; + } + + if (*io_len + 1ULL + comp_len >= path_size) { + return 0; + } + + path[*io_len] = '/'; + for (i = 0ULL; i < comp_len; i++) { + path[*io_len + 1ULL + i] = component[i]; + } + + *io_len += (1ULL + comp_len); + path[*io_len] = '\0'; + return 1; +} + +static void ush_path_pop_component(char *path, u64 *io_len) { + if (path == (char *)0 || io_len == (u64 *)0) { + return; + } + + if (*io_len <= 1ULL) { + path[0] = '/'; + path[1] = '\0'; + *io_len = 1ULL; + return; + } + + while (*io_len > 1ULL && path[*io_len - 1ULL] != '/') { + (*io_len)--; + } + + if (*io_len > 1ULL) { + (*io_len)--; + } + + path[*io_len] = '\0'; +} + +static int ush_path_parse_into(const char *src, char *out_path, u64 out_size, u64 *io_len) { + u64 i = 0ULL; + + if (src == (const char *)0 || out_path == (char *)0 || io_len == (u64 *)0) { + return 0; + } + + if (src[0] == '/') { + i = 1ULL; + } + + while (src[i] != '\0') { + u64 start; + u64 len; + + while (src[i] == '/') { + i++; + } + + if (src[i] == '\0') { + break; + } + + start = i; + + while (src[i] != '\0' && src[i] != '/') { + i++; + } + + len = i - start; + + if (len == 1ULL && src[start] == '.') { + continue; + } + + if (len == 2ULL && src[start] == '.' && src[start + 1ULL] == '.') { + ush_path_pop_component(out_path, io_len); + continue; + } + + if (ush_path_push_component(out_path, out_size, io_len, src + start, len) == 0) { + return 0; + } + } + + return 1; +} + +int ush_resolve_path(const ush_state *sh, const char *arg, char *out_path, u64 out_size) { + u64 len = 1ULL; + + if (sh == (const ush_state *)0 || out_path == (char *)0 || out_size < 2ULL) { + return 0; + } + + out_path[0] = '/'; + out_path[1] = '\0'; + + if (arg == (const char *)0 || arg[0] == '\0') { + return ush_path_parse_into(sh->cwd, out_path, out_size, &len); + } + + if (arg[0] != '/') { + if (ush_path_parse_into(sh->cwd, out_path, out_size, &len) == 0) { + return 0; + } + } + + return ush_path_parse_into(arg, out_path, out_size, &len); +} + +int ush_resolve_exec_path(const ush_state *sh, const char *arg, char *out_path, u64 out_size) { + u64 i; + u64 cursor = 0ULL; + + if (sh == (const ush_state *)0 || arg == (const char *)0 || out_path == (char *)0 || out_size == 0ULL) { + return 0; + } + + if (arg[0] == '\0') { + return 0; + } + + out_path[0] = '\0'; + + if (arg[0] == '/') { + ush_copy(out_path, out_size, arg); + } else if (ush_contains_char(arg, '/') != 0) { + if (ush_resolve_path(sh, arg, out_path, out_size) == 0) { + return 0; + } + } else { + static const char prefix[] = "/shell/"; + u64 prefix_len = (u64)(sizeof(prefix) - 1U); + + if (prefix_len + 1ULL >= out_size) { + return 0; + } + + for (i = 0ULL; i < prefix_len; i++) { + out_path[cursor++] = prefix[i]; + } + + for (i = 0ULL; arg[i] != '\0'; i++) { + if (cursor + 1ULL >= out_size) { + return 0; + } + out_path[cursor++] = arg[i]; + } + + out_path[cursor] = '\0'; + } + + if (ush_has_suffix(out_path, ".elf") == 0) { + static const char suffix[] = ".elf"; + + cursor = ush_strlen(out_path); + + for (i = 0ULL; suffix[i] != '\0'; i++) { + if (cursor + 1ULL >= out_size) { + return 0; + } + out_path[cursor++] = suffix[i]; + } + + out_path[cursor] = '\0'; + } + + return 1; +} + +int ush_path_is_under_system(const char *path) { + if (path == (const char *)0) { + return 0; + } + + if (path[0] != '/' || path[1] != 's' || path[2] != 'y' || path[3] != 's' || path[4] != 't' || path[5] != 'e' || path[6] != 'm') { + return 0; + } + + return (path[7] == '\0' || path[7] == '/') ? 1 : 0; +} + +int ush_path_is_under_temp(const char *path) { + if (path == (const char *)0) { + return 0; + } + + if (path[0] != '/' || path[1] != 't' || path[2] != 'e' || path[3] != 'm' || path[4] != 'p') { + return 0; + } + + return (path[5] == '\0' || path[5] == '/') ? 1 : 0; +} + +int ush_split_first_and_rest(const char *arg, char *out_first, u64 out_first_size, const char **out_rest) { + u64 i = 0ULL; + u64 p = 0ULL; + + if (arg == (const char *)0 || out_first == (char *)0 || out_first_size == 0ULL || out_rest == (const char **)0) { + return 0; + } + + out_first[0] = '\0'; + *out_rest = ""; + + while (arg[i] != '\0' && ush_is_space(arg[i]) != 0) { + i++; + } + + if (arg[i] == '\0') { + return 0; + } + + while (arg[i] != '\0' && ush_is_space(arg[i]) == 0) { + if (p + 1ULL < out_first_size) { + out_first[p++] = arg[i]; + } + i++; + } + + out_first[p] = '\0'; + + while (arg[i] != '\0' && ush_is_space(arg[i]) != 0) { + i++; + } + + *out_rest = &arg[i]; + return 1; +} + +int ush_split_two_args(const char *arg, + char *out_first, + u64 out_first_size, + char *out_second, + u64 out_second_size) { + u64 i = 0ULL; + u64 p = 0ULL; + + if (arg == (const char *)0 || + out_first == (char *)0 || out_first_size == 0ULL || + out_second == (char *)0 || out_second_size == 0ULL) { + return 0; + } + + out_first[0] = '\0'; + out_second[0] = '\0'; + + while (arg[i] != '\0' && ush_is_space(arg[i]) != 0) { + i++; + } + + if (arg[i] == '\0') { + return 0; + } + + while (arg[i] != '\0' && ush_is_space(arg[i]) == 0) { + if (p + 1ULL < out_first_size) { + out_first[p++] = arg[i]; + } + i++; + } + + out_first[p] = '\0'; + + while (arg[i] != '\0' && ush_is_space(arg[i]) != 0) { + i++; + } + + if (arg[i] == '\0') { + return 0; + } + + p = 0ULL; + while (arg[i] != '\0' && ush_is_space(arg[i]) == 0) { + if (p + 1ULL < out_second_size) { + out_second[p++] = arg[i]; + } + i++; + } + + out_second[p] = '\0'; + + return (out_first[0] != '\0' && out_second[0] != '\0') ? 1 : 0; +} + +int ush_command_ctx_read(ush_cmd_ctx *out_ctx) { + u64 got; + + if (out_ctx == (ush_cmd_ctx *)0) { + return 0; + } + + ush_zero(out_ctx, (u64)sizeof(*out_ctx)); + got = cleonos_sys_fs_read(USH_CMD_CTX_PATH, (char *)out_ctx, (u64)sizeof(*out_ctx)); + return (got == (u64)sizeof(*out_ctx)) ? 1 : 0; +} + +int ush_command_ret_write(const ush_cmd_ret *ret) { + if (ret == (const ush_cmd_ret *)0) { + return 0; + } + + return (cleonos_sys_fs_write(USH_CMD_RET_PATH, (const char *)ret, (u64)sizeof(*ret)) != 0ULL) ? 1 : 0; +} diff --git a/cleonos/c/apps/cmd_runtime.h b/cleonos/c/apps/cmd_runtime.h new file mode 100644 index 0000000..06005ab --- /dev/null +++ b/cleonos/c/apps/cmd_runtime.h @@ -0,0 +1,98 @@ +#ifndef CLEONOS_CMD_RUNTIME_H +#define CLEONOS_CMD_RUNTIME_H + +#include + +typedef long long i64; + +#define USH_CMD_MAX 32ULL +#define USH_ARG_MAX 160ULL +#define USH_LINE_MAX 192ULL +#define USH_PATH_MAX 192ULL +#define USH_CAT_MAX 512ULL +#define USH_SCRIPT_MAX 1024ULL +#define USH_CLEAR_LINES 56ULL +#define USH_HISTORY_MAX 16ULL +#define USH_DMESG_DEFAULT 64ULL +#define USH_DMESG_LINE_MAX 256ULL +#define USH_COPY_MAX 65536U + +#define USH_CMD_CTX_PATH "/temp/.ush_cmd_ctx.bin" +#define USH_CMD_RET_PATH "/temp/.ush_cmd_ret.bin" +#define USH_CMD_RET_FLAG_CWD 0x1ULL +#define USH_CMD_RET_FLAG_EXIT 0x2ULL + +typedef struct ush_state { + char line[USH_LINE_MAX]; + u64 line_len; + u64 cursor; + u64 rendered_len; + + char cwd[USH_PATH_MAX]; + + char history[USH_HISTORY_MAX][USH_LINE_MAX]; + u64 history_count; + i64 history_nav; + char nav_saved_line[USH_LINE_MAX]; + u64 nav_saved_len; + u64 nav_saved_cursor; + + u64 cmd_total; + u64 cmd_ok; + u64 cmd_fail; + u64 cmd_unknown; + int exit_requested; + u64 exit_code; +} ush_state; + +typedef struct ush_cmd_ctx { + char cmd[USH_CMD_MAX]; + char arg[USH_ARG_MAX]; + char cwd[USH_PATH_MAX]; +} ush_cmd_ctx; + +typedef struct ush_cmd_ret { + u64 flags; + u64 exit_code; + char cwd[USH_PATH_MAX]; +} ush_cmd_ret; + +extern const char *ush_pipeline_stdin_text; +extern u64 ush_pipeline_stdin_len; + +void ush_zero(void *ptr, u64 size); +void ush_init_state(ush_state *sh); + +u64 ush_strlen(const char *str); +int ush_streq(const char *left, const char *right); +int ush_is_space(char ch); +int ush_is_printable(char ch); +int ush_has_suffix(const char *name, const char *suffix); +int ush_contains_char(const char *text, char needle); +int ush_parse_u64_dec(const char *text, u64 *out_value); +void ush_copy(char *dst, u64 dst_size, const char *src); +void ush_trim_line(char *line); +void ush_parse_line(const char *line, char *out_cmd, u64 cmd_size, char *out_arg, u64 arg_size); + +void ush_write(const char *text); +void ush_write_char(char ch); +void ush_writeln(const char *text); +void ush_write_hex_u64(u64 value); +void ush_print_kv_hex(const char *label, u64 value); + +int ush_resolve_path(const ush_state *sh, const char *arg, char *out_path, u64 out_size); +int ush_resolve_exec_path(const ush_state *sh, const char *arg, char *out_path, u64 out_size); +int ush_path_is_under_system(const char *path); +int ush_path_is_under_temp(const char *path); + +int ush_split_first_and_rest(const char *arg, char *out_first, u64 out_first_size, const char **out_rest); +int ush_split_two_args(const char *arg, + char *out_first, + u64 out_first_size, + char *out_second, + u64 out_second_size); + +int ush_command_ctx_read(ush_cmd_ctx *out_ctx); +int ush_command_ret_write(const ush_cmd_ret *ret); + +#endif diff --git a/cleonos/c/apps/cp_main.c b/cleonos/c/apps/cp_main.c index 475163b..6681ea9 100644 --- a/cleonos/c/apps/cp_main.c +++ b/cleonos/c/apps/cp_main.c @@ -1,6 +1,120 @@ -#include "shell/shell_internal.h" +#include "cmd_runtime.h" +static int ush_copy_file(const char *src_path, const char *dst_path) { + static char copy_buf[USH_COPY_MAX]; + u64 src_type; + u64 src_size; + u64 got; -int cleonos_app_main(void) { - return ush_command_program_main("cp"); + src_type = cleonos_sys_fs_stat_type(src_path); + + if (src_type != 1ULL) { + ush_writeln("cp: source file not found"); + return 0; + } + + src_size = cleonos_sys_fs_stat_size(src_path); + + if (src_size == (u64)-1) { + ush_writeln("cp: failed to stat source"); + return 0; + } + + if (src_size > (u64)USH_COPY_MAX) { + ush_writeln("cp: source too large for user shell buffer"); + return 0; + } + + if (src_size == 0ULL) { + got = 0ULL; + } else { + got = cleonos_sys_fs_read(src_path, copy_buf, src_size); + + if (got == 0ULL || got != src_size) { + ush_writeln("cp: failed to read source"); + return 0; + } + } + + if (cleonos_sys_fs_write(dst_path, copy_buf, got) == 0ULL) { + ush_writeln("cp: failed to write destination"); + return 0; + } + + return 1; +} + +static int ush_cmd_cp(const ush_state *sh, const char *arg) { + char src_arg[USH_PATH_MAX]; + char dst_arg[USH_PATH_MAX]; + char src_path[USH_PATH_MAX]; + char dst_path[USH_PATH_MAX]; + + if (arg == (const char *)0 || arg[0] == '\0') { + ush_writeln("cp: usage cp "); + return 0; + } + + if (ush_split_two_args(arg, src_arg, (u64)sizeof(src_arg), dst_arg, (u64)sizeof(dst_arg)) == 0) { + ush_writeln("cp: usage cp "); + return 0; + } + + if (ush_resolve_path(sh, src_arg, src_path, (u64)sizeof(src_path)) == 0 || + ush_resolve_path(sh, dst_arg, dst_path, (u64)sizeof(dst_path)) == 0) { + ush_writeln("cp: invalid path"); + return 0; + } + + if (ush_path_is_under_temp(dst_path) == 0) { + ush_writeln("cp: destination must be under /temp"); + return 0; + } + + return ush_copy_file(src_path, dst_path); +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + const char *arg = ""; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "cp") != 0) { + has_context = 1; + arg = ctx.arg; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_cp(&sh, arg); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/dmesg_main.c b/cleonos/c/apps/dmesg_main.c index 385fa36..2d5987b 100644 --- a/cleonos/c/apps/dmesg_main.c +++ b/cleonos/c/apps/dmesg_main.c @@ -1,6 +1,81 @@ -#include "shell/shell_internal.h" +#include "cmd_runtime.h" +static int ush_cmd_dmesg(const char *arg) { + u64 total = cleonos_sys_log_journal_count(); + u64 limit = USH_DMESG_DEFAULT; + u64 start; + u64 i; -int cleonos_app_main(void) { - return ush_command_program_main("dmesg"); + if (arg != (const char *)0 && arg[0] != '\0') { + if (ush_parse_u64_dec(arg, &limit) == 0 || limit == 0ULL) { + ush_writeln("dmesg: usage dmesg [positive_count]"); + return 0; + } + } + + if (total == 0ULL) { + ush_writeln("(journal empty)"); + return 1; + } + + if (limit > total) { + limit = total; + } + + start = total - limit; + + for (i = start; i < total; i++) { + char line[USH_DMESG_LINE_MAX]; + + if (cleonos_sys_log_journal_read(i, line, (u64)sizeof(line)) != 0ULL) { + ush_writeln(line); + } + } + + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + const char *arg = ""; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "dmesg") != 0) { + has_context = 1; + arg = ctx.arg; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_dmesg(arg); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/exec_main.c b/cleonos/c/apps/exec_main.c index e30f326..1752e81 100644 --- a/cleonos/c/apps/exec_main.c +++ b/cleonos/c/apps/exec_main.c @@ -1,6 +1,76 @@ -#include "shell/shell_internal.h" +#include "cmd_runtime.h" +static int ush_cmd_exec(const ush_state *sh, const char *arg) { + char path[USH_PATH_MAX]; + u64 status; -int cleonos_app_main(void) { - return ush_command_program_main("exec"); + if (ush_resolve_exec_path(sh, arg, path, (u64)sizeof(path)) == 0) { + ush_writeln("exec: invalid target"); + return 0; + } + + if (ush_path_is_under_system(path) != 0) { + ush_writeln("exec: /system/*.elf is kernel-mode (KELF), not user-exec"); + return 0; + } + + status = cleonos_sys_exec_path(path); + + if (status == (u64)-1) { + ush_writeln("exec: request failed"); + return 0; + } + + if (status == 0ULL) { + ush_writeln("exec: request accepted"); + return 1; + } + + ush_writeln("exec: returned non-zero status"); + return 0; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + const char *arg = ""; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "exec") != 0) { + has_context = 1; + arg = ctx.arg; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_exec(&sh, arg); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/exit_main.c b/cleonos/c/apps/exit_main.c index f7d7e0f..18d5dd9 100644 --- a/cleonos/c/apps/exit_main.c +++ b/cleonos/c/apps/exit_main.c @@ -1,6 +1,67 @@ -#include "shell/shell_internal.h" +#include "cmd_runtime.h" +static int ush_cmd_exit(ush_state *sh, const char *arg) { + u64 code = 0ULL; -int cleonos_app_main(void) { - return ush_command_program_main("exit"); + if (sh == (ush_state *)0) { + return 0; + } + + if (arg != (const char *)0 && arg[0] != '\0') { + if (ush_parse_u64_dec(arg, &code) == 0) { + ush_writeln("exit: usage exit [code]"); + return 0; + } + } + + sh->exit_requested = 1; + sh->exit_code = code; + (void)cleonos_sys_exit(code); + ush_writeln("exit: shell stopping"); + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + const char *arg = ""; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "exit") != 0) { + has_context = 1; + arg = ctx.arg; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_exit(&sh, arg); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/fastfetch_main.c b/cleonos/c/apps/fastfetch_main.c index e8d0d26..1069804 100644 --- a/cleonos/c/apps/fastfetch_main.c +++ b/cleonos/c/apps/fastfetch_main.c @@ -1,5 +1,213 @@ -#include "shell/shell_internal.h" +#include "cmd_runtime.h" +static u64 ush_fastfetch_u64_to_dec(char *out, u64 out_size, u64 value) { + char rev[32]; + u64 digits = 0ULL; + u64 i; + + if (out == (char *)0 || out_size == 0ULL) { + return 0ULL; + } + + if (value == 0ULL) { + if (out_size < 2ULL) { + return 0ULL; + } + out[0] = '0'; + out[1] = '\0'; + return 1ULL; + } + + while (value > 0ULL && digits < (u64)sizeof(rev)) { + rev[digits++] = (char)('0' + (value % 10ULL)); + value /= 10ULL; + } + + if (digits + 1ULL > out_size) { + out[0] = '\0'; + return 0ULL; + } + + for (i = 0ULL; i < digits; i++) { + out[i] = rev[digits - 1ULL - i]; + } + out[digits] = '\0'; + return digits; +} + +static void ush_fastfetch_write_u64_dec(u64 value) { + char text[32]; + + if (ush_fastfetch_u64_to_dec(text, (u64)sizeof(text), value) == 0ULL) { + ush_write("0"); + return; + } + + ush_write(text); +} + +static void ush_fastfetch_write_key(int plain, const char *key) { + ush_write(" "); + if (plain == 0) { + ush_write("\x1B[1;96m"); + } + ush_write(key); + if (plain == 0) { + ush_write("\x1B[0m"); + } + ush_write(": "); +} + +static void ush_fastfetch_print_text(int plain, const char *key, const char *value) { + ush_fastfetch_write_key(plain, key); + ush_writeln(value); +} + +static void ush_fastfetch_print_u64(int plain, const char *key, u64 value) { + ush_fastfetch_write_key(plain, key); + ush_fastfetch_write_u64_dec(value); + ush_write_char('\n'); +} + +static void ush_fastfetch_print_logo(int plain) { + if (plain == 0) { + ush_writeln("\x1B[1;34m $$$$$$\\ $$\\ $$$$$$\\ $$$$$$\\ \x1B[0m"); + ush_writeln("\x1B[1;36m$$ __$$\\ $$ | $$ __$$\\ $$ __$$\\ \x1B[0m"); + ush_writeln("\x1B[1;32m$$ / \\__|$$ | $$$$$$\\ $$$$$$\\ $$$$$$$\\ $$ / $$ |$$ / \\__|\x1B[0m"); + ush_writeln("\x1B[1;33m$$ | $$ | $$ __$$\\ $$ __$$\\ $$ __$$\\ $$ | $$ |\\$$$$$$\\ \x1B[0m"); + ush_writeln("\x1B[1;31m$$ | $$ | $$$$$$$$ |$$ / $$ |$$ | $$ |$$ | $$ | \\____$$\\ \x1B[0m"); + ush_writeln("\x1B[1;35m$$ | $$\\ $$ | $$ ____|$$ | $$ |$$ | $$ |$$ | $$ |$$\\ $$ |\x1B[0m"); + ush_writeln("\x1B[1;94m\\$$$$$$ |$$$$$$$$\\ \\$$$$$$$\\ \\$$$$$$ |$$ | $$ | $$$$$$ |\\$$$$$$ |\x1B[0m"); + ush_writeln("\x1B[1;96m \\______/ \\________| \\_______| \\______/ \\__| \\__| \\______/ \\______/ \x1B[0m"); + ush_writeln(" "); + ush_writeln(" "); + } else { + ush_writeln(" $$$$$$\\ $$\\ $$$$$$\\ $$$$$$\\ "); + ush_writeln("$$ __$$\\ $$ | $$ __$$\\ $$ __$$\\ "); + ush_writeln("$$ / \\__|$$ | $$$$$$\\ $$$$$$\\ $$$$$$$\\ $$ / $$ |$$ / \\__|"); + ush_writeln("$$ | $$ | $$ __$$\\ $$ __$$\\ $$ __$$\\ $$ | $$ |\\$$$$$$\\ "); + ush_writeln("$$ | $$ | $$$$$$$$ |$$ / $$ |$$ | $$ |$$ | $$ | \\____$$\\ "); + ush_writeln("$$ | $$\\ $$ | $$ ____|$$ | $$ |$$ | $$ |$$ | $$ |$$\\ $$ |"); + ush_writeln("\\$$$$$$ |$$$$$$$$\\ \\$$$$$$$\\ \\$$$$$$ |$$ | $$ | $$$$$$ |\\$$$$$$ |"); + ush_writeln(" \\______/ \\________| \\_______| \\______/ \\__| \\__| \\______/ \\______/ "); + ush_writeln(" "); + ush_writeln(" "); + } +} + +static void ush_fastfetch_print_palette(int plain) { + ush_fastfetch_write_key(plain, "Palette"); + + if (plain != 0) { + ush_writeln("ANSI16"); + return; + } + + ush_write("\x1B[40m \x1B[0m\x1B[41m \x1B[0m\x1B[42m \x1B[0m\x1B[43m \x1B[0m"); + ush_write("\x1B[44m \x1B[0m\x1B[45m \x1B[0m\x1B[46m \x1B[0m\x1B[47m \x1B[0m "); + ush_write("\x1B[100m \x1B[0m\x1B[101m \x1B[0m\x1B[102m \x1B[0m\x1B[103m \x1B[0m"); + ush_write("\x1B[104m \x1B[0m\x1B[105m \x1B[0m\x1B[106m \x1B[0m\x1B[107m \x1B[0m"); + ush_write_char('\n'); +} + +static int ush_cmd_fastfetch(const char *arg) { + int plain = 0; + u64 tty_active; + u64 tty_count; + u64 exec_req; + u64 exec_ok; + + if (arg != (const char *)0 && arg[0] != '\0') { + if (ush_streq(arg, "--plain") != 0) { + plain = 1; + } else if (ush_streq(arg, "--help") != 0 || ush_streq(arg, "-h") != 0) { + ush_writeln("usage: fastfetch [--plain]"); + return 1; + } else { + ush_writeln("fastfetch: usage fastfetch [--plain]"); + return 0; + } + } + + tty_active = cleonos_sys_tty_active(); + tty_count = cleonos_sys_tty_count(); + exec_req = cleonos_sys_exec_request_count(); + exec_ok = cleonos_sys_exec_success_count(); + + ush_fastfetch_print_logo(plain); + ush_write_char('\n'); + + ush_fastfetch_print_text(plain, "OS", "CLeonOS x86_64"); + ush_fastfetch_print_text(plain, "Shell", "User Shell (/shell/shell.elf)"); + ush_fastfetch_print_u64(plain, "PID", cleonos_sys_getpid()); + ush_fastfetch_print_u64(plain, "UptimeTicks", cleonos_sys_timer_ticks()); + ush_fastfetch_print_u64(plain, "Tasks", cleonos_sys_task_count()); + ush_fastfetch_print_u64(plain, "Services", cleonos_sys_service_count()); + ush_fastfetch_print_u64(plain, "SvcReady", cleonos_sys_service_ready_count()); + ush_fastfetch_print_u64(plain, "CtxSwitches", cleonos_sys_context_switches()); + ush_fastfetch_print_u64(plain, "KELFApps", cleonos_sys_kelf_count()); + ush_fastfetch_print_u64(plain, "KELFRuns", cleonos_sys_kelf_runs()); + ush_fastfetch_print_u64(plain, "FSNodes", cleonos_sys_fs_node_count()); + ush_fastfetch_print_u64(plain, "RootChildren", cleonos_sys_fs_child_count("/")); + + ush_fastfetch_write_key(plain, "TTY"); + ush_fastfetch_write_u64_dec(tty_active); + ush_write(" / "); + ush_fastfetch_write_u64_dec(tty_count); + ush_write_char('\n'); + + ush_fastfetch_write_key(plain, "ExecSuccess"); + ush_fastfetch_write_u64_dec(exec_ok); + ush_write(" / "); + ush_fastfetch_write_u64_dec(exec_req); + ush_write_char('\n'); + + ush_fastfetch_print_u64(plain, "KbdBuffered", cleonos_sys_kbd_buffered()); + ush_fastfetch_print_palette(plain); + return 1; +} + int cleonos_app_main(void) { - return ush_command_program_main("fastfetch"); + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + const char *arg = ""; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "fastfetch") != 0) { + has_context = 1; + arg = ctx.arg; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_fastfetch(arg); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } + diff --git a/cleonos/c/apps/fsstat_main.c b/cleonos/c/apps/fsstat_main.c index 2d6707d..bf713aa 100644 --- a/cleonos/c/apps/fsstat_main.c +++ b/cleonos/c/apps/fsstat_main.c @@ -1,6 +1,55 @@ -#include "shell/shell_internal.h" - -int cleonos_app_main(void) { - return ush_command_program_main("fsstat"); +#include "cmd_runtime.h" +static int ush_cmd_fsstat(void) { + ush_writeln("fsstat:"); + ush_print_kv_hex(" NODE_COUNT", cleonos_sys_fs_node_count()); + ush_print_kv_hex(" ROOT_CHILDREN", cleonos_sys_fs_child_count("/")); + ush_print_kv_hex(" SYSTEM_CHILDREN", cleonos_sys_fs_child_count("/system")); + ush_print_kv_hex(" SHELL_CHILDREN", cleonos_sys_fs_child_count("/shell")); + ush_print_kv_hex(" TEMP_CHILDREN", cleonos_sys_fs_child_count("/temp")); + ush_print_kv_hex(" DRIVER_CHILDREN", cleonos_sys_fs_child_count("/driver")); + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "fsstat") != 0) { + has_context = 1; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_fsstat(); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/grep_main.c b/cleonos/c/apps/grep_main.c index 3bd078e..8a9d785 100644 --- a/cleonos/c/apps/grep_main.c +++ b/cleonos/c/apps/grep_main.c @@ -1,5 +1,248 @@ -#include "shell/shell_internal.h" +#include "cmd_runtime.h" +static void ush_grep_write_u64_dec(u64 value) { + char tmp[32]; + u64 len = 0ULL; + + if (value == 0ULL) { + ush_write_char('0'); + return; + } + + while (value > 0ULL && len < (u64)sizeof(tmp)) { + tmp[len++] = (char)('0' + (value % 10ULL)); + value /= 10ULL; + } + + while (len > 0ULL) { + len--; + ush_write_char(tmp[len]); + } +} + +static int ush_grep_line_has_pattern(const char *line, u64 line_len, const char *pattern, u64 pattern_len) { + u64 i; + + if (line == (const char *)0 || pattern == (const char *)0) { + return 0; + } + + if (pattern_len == 0ULL) { + return 1; + } + + if (pattern_len > line_len) { + return 0; + } + + for (i = 0ULL; i + pattern_len <= line_len; i++) { + u64 j = 0ULL; + + while (j < pattern_len && line[i + j] == pattern[j]) { + j++; + } + + if (j == pattern_len) { + return 1; + } + } + + return 0; +} + +static u64 ush_grep_emit_matches(const char *input, u64 input_len, const char *pattern, int with_line_number) { + u64 matches = 0ULL; + u64 line_no = 1ULL; + u64 start = 0ULL; + u64 i; + u64 pattern_len; + + if (input == (const char *)0 || pattern == (const char *)0) { + return 0ULL; + } + + pattern_len = ush_strlen(pattern); + + for (i = 0ULL; i <= input_len; i++) { + if (i == input_len || input[i] == '\n') { + u64 line_len = i - start; + + if (ush_grep_line_has_pattern(&input[start], line_len, pattern, pattern_len) != 0) { + u64 j; + + matches++; + + if (with_line_number != 0) { + ush_grep_write_u64_dec(line_no); + ush_write(":"); + } + + for (j = 0ULL; j < line_len; j++) { + ush_write_char(input[start + j]); + } + + ush_write_char('\n'); + } + + start = i + 1ULL; + line_no++; + } + } + + return matches; +} + +static int ush_cmd_grep(const ush_state *sh, const char *arg) { + char first[USH_PATH_MAX]; + char second[USH_PATH_MAX]; + char third[USH_PATH_MAX]; + char path[USH_PATH_MAX]; + const char *rest = ""; + const char *rest2 = ""; + const char *pattern = (const char *)0; + const char *file_arg = (const char *)0; + const char *input = (const char *)0; + u64 input_len = 0ULL; + u64 size; + u64 got; + int with_line_number = 0; + static char file_buf[USH_COPY_MAX + 1U]; + + if (sh == (const ush_state *)0 || arg == (const char *)0 || arg[0] == '\0') { + ush_writeln("grep: usage grep [-n] [file]"); + return 0; + } + + if (ush_split_first_and_rest(arg, first, (u64)sizeof(first), &rest) == 0) { + ush_writeln("grep: usage grep [-n] [file]"); + return 0; + } + + if (ush_streq(first, "-n") != 0) { + with_line_number = 1; + + if (ush_split_first_and_rest(rest, second, (u64)sizeof(second), &rest2) == 0) { + ush_writeln("grep: usage grep [-n] [file]"); + return 0; + } + + pattern = second; + rest = rest2; + } else { + pattern = first; + } + + if (rest != (const char *)0 && rest[0] != '\0') { + if (ush_split_first_and_rest(rest, third, (u64)sizeof(third), &rest2) == 0) { + ush_writeln("grep: usage grep [-n] [file]"); + return 0; + } + + file_arg = third; + + if (rest2 != (const char *)0 && rest2[0] != '\0') { + ush_writeln("grep: usage grep [-n] [file]"); + return 0; + } + } + + if (pattern == (const char *)0 || pattern[0] == '\0') { + ush_writeln("grep: pattern required"); + return 0; + } + + if (file_arg != (const char *)0) { + if (ush_resolve_path(sh, file_arg, path, (u64)sizeof(path)) == 0) { + ush_writeln("grep: invalid path"); + return 0; + } + + if (cleonos_sys_fs_stat_type(path) != 1ULL) { + ush_writeln("grep: file not found"); + return 0; + } + + size = cleonos_sys_fs_stat_size(path); + + if (size == (u64)-1) { + ush_writeln("grep: failed to stat file"); + return 0; + } + + if (size > (u64)USH_COPY_MAX) { + ush_writeln("grep: file too large for user buffer"); + return 0; + } + + if (size == 0ULL) { + return 1; + } + + got = cleonos_sys_fs_read(path, file_buf, size); + + if (got == 0ULL || got != size) { + ush_writeln("grep: read failed"); + return 0; + } + + file_buf[got] = '\0'; + input = file_buf; + input_len = got; + } else { + if (ush_pipeline_stdin_text == (const char *)0) { + ush_writeln("grep: file path required (or pipeline input)"); + return 0; + } + + input = ush_pipeline_stdin_text; + input_len = ush_pipeline_stdin_len; + } + + (void)ush_grep_emit_matches(input, input_len, pattern, with_line_number); + return 1; +} + int cleonos_app_main(void) { - return ush_command_program_main("grep"); + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + const char *arg = ""; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "grep") != 0) { + has_context = 1; + arg = ctx.arg; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_grep(&sh, arg); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } + diff --git a/cleonos/c/apps/help_main.c b/cleonos/c/apps/help_main.c index 45a7986..4df9b2c 100644 --- a/cleonos/c/apps/help_main.c +++ b/cleonos/c/apps/help_main.c @@ -1,6 +1,81 @@ -#include "shell/shell_internal.h" - -int cleonos_app_main(void) { - return ush_command_program_main("help"); +#include "cmd_runtime.h" +static int ush_cmd_help(void) { + ush_writeln("commands:"); + ush_writeln(" help"); + ush_writeln(" ls [-l] [-R] [path]"); + ush_writeln(" cat [file] (reads pipeline input when file omitted)"); + ush_writeln(" grep [-n] [file]"); + ush_writeln(" pwd"); + ush_writeln(" cd [dir]"); + ush_writeln(" exec|run "); + ush_writeln(" clear"); + ush_writeln(" ansi / ansitest / color"); + ush_writeln(" fastfetch [--plain]"); + ush_writeln(" memstat / fsstat / taskstat / userstat / shstat / stats"); + ush_writeln(" tty [index]"); + ush_writeln(" dmesg [n]"); + ush_writeln(" kbdstat"); + ush_writeln(" mkdir (/temp only)"); + ush_writeln(" touch (/temp only)"); + ush_writeln(" write (/temp only, or from pipeline)"); + ush_writeln(" append (/temp only, or from pipeline)"); + ush_writeln(" cp (dst /temp only)"); + ush_writeln(" mv (/temp only)"); + ush_writeln(" rm (/temp only)"); + ush_writeln(" pid"); + ush_writeln(" spawn "); + ush_writeln(" wait "); + ush_writeln(" sleep "); + ush_writeln(" yield"); + ush_writeln(" shutdown / restart"); + ush_writeln(" exit [code]"); + ush_writeln(" rusttest / panic / elfloader (kernel shell only)"); + ush_writeln("pipeline/redirection: cmd1 | cmd2 | cmd3 > /temp/out.txt"); + ush_writeln("redirection append: cmd >> /temp/out.txt"); + ush_writeln("edit keys: Left/Right, Home/End, Up/Down history"); + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "help") != 0) { + has_context = 1; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_help(); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/kbdstat_main.c b/cleonos/c/apps/kbdstat_main.c index c6dd585..8026850 100644 --- a/cleonos/c/apps/kbdstat_main.c +++ b/cleonos/c/apps/kbdstat_main.c @@ -1,6 +1,54 @@ -#include "shell/shell_internal.h" - -int cleonos_app_main(void) { - return ush_command_program_main("kbdstat"); +#include "cmd_runtime.h" +static int ush_cmd_kbdstat(void) { + ush_writeln("kbdstat:"); + ush_print_kv_hex(" BUFFERED", cleonos_sys_kbd_buffered()); + ush_print_kv_hex(" PUSHED", cleonos_sys_kbd_pushed()); + ush_print_kv_hex(" POPPED", cleonos_sys_kbd_popped()); + ush_print_kv_hex(" DROPPED", cleonos_sys_kbd_dropped()); + ush_print_kv_hex(" HOTKEY_SWITCHES", cleonos_sys_kbd_hotkey_switches()); + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "kbdstat") != 0) { + has_context = 1; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_kbdstat(); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/ls_main.c b/cleonos/c/apps/ls_main.c index 4286037..9bcb465 100644 --- a/cleonos/c/apps/ls_main.c +++ b/cleonos/c/apps/ls_main.c @@ -1,6 +1,337 @@ -#include "shell/shell_internal.h" +#include "cmd_runtime.h" +static int ush_ls_join_path(const char *dir_path, const char *name, char *out_path, u64 out_size) { + u64 p = 0ULL; + u64 i; -int cleonos_app_main(void) { - return ush_command_program_main("ls"); + if (dir_path == (const char *)0 || name == (const char *)0 || out_path == (char *)0 || out_size == 0ULL) { + return 0; + } + + if (dir_path[0] == '/' && dir_path[1] == '\0') { + if (out_size < 2ULL) { + return 0; + } + + out_path[p++] = '/'; + } else { + for (i = 0ULL; dir_path[i] != '\0'; i++) { + if (p + 1ULL >= out_size) { + return 0; + } + + out_path[p++] = dir_path[i]; + } + + if (p == 0ULL || out_path[p - 1ULL] != '/') { + if (p + 1ULL >= out_size) { + return 0; + } + + out_path[p++] = '/'; + } + } + + for (i = 0ULL; name[i] != '\0'; i++) { + if (p + 1ULL >= out_size) { + return 0; + } + + out_path[p++] = name[i]; + } + + out_path[p] = '\0'; + return 1; +} + +static const char *ush_ls_basename(const char *path) { + const char *name = path; + u64 i = 0ULL; + + if (path == (const char *)0 || path[0] == '\0') { + return ""; + } + + while (path[i] != '\0') { + if (path[i] == '/' && path[i + 1ULL] != '\0') { + name = &path[i + 1ULL]; + } + + i++; + } + + return name; +} + +static int ush_ls_is_dot_entry(const char *name) { + if (name == (const char *)0) { + return 0; + } + + if (name[0] == '.' && name[1] == '\0') { + return 1; + } + + if (name[0] == '.' && name[1] == '.' && name[2] == '\0') { + return 1; + } + + return 0; +} + +static void ush_ls_print_one(const char *name, u64 type, u64 size, int long_mode) { + if (long_mode == 0) { + ush_writeln(name); + return; + } + + if (type == 2ULL) { + ush_write("d "); + } else if (type == 1ULL) { + ush_write("f "); + } else { + ush_write("? "); + } + + ush_write(name); + + if (type == 1ULL) { + ush_write(" size="); + ush_write_hex_u64(size); + } else if (type == 2ULL) { + ush_write(" "); + } else { + ush_write(" "); + } + + ush_write_char('\n'); +} + +static int ush_ls_parse_args(const char *arg, + int *out_long_mode, + int *out_recursive, + char *out_target, + u64 out_target_size) { + char token[USH_PATH_MAX]; + u64 i = 0ULL; + int path_set = 0; + + if (out_long_mode == (int *)0 || + out_recursive == (int *)0 || + out_target == (char *)0 || + out_target_size == 0ULL) { + return 0; + } + + *out_long_mode = 0; + *out_recursive = 0; + ush_copy(out_target, out_target_size, "."); + + if (arg == (const char *)0 || arg[0] == '\0') { + return 1; + } + + while (arg[i] != '\0') { + u64 p = 0ULL; + u64 j; + + while (arg[i] != '\0' && ush_is_space(arg[i]) != 0) { + i++; + } + + if (arg[i] == '\0') { + break; + } + + while (arg[i] != '\0' && ush_is_space(arg[i]) == 0) { + if (p + 1ULL < (u64)sizeof(token)) { + token[p++] = arg[i]; + } + + i++; + } + + token[p] = '\0'; + + if (token[0] == '-' && token[1] != '\0') { + for (j = 1ULL; token[j] != '\0'; j++) { + if (token[j] == 'l') { + *out_long_mode = 1; + } else if (token[j] == 'R') { + *out_recursive = 1; + } else { + return 0; + } + } + + continue; + } + + if (path_set != 0) { + return 0; + } + + ush_copy(out_target, out_target_size, token); + path_set = 1; + } + + return 1; +} + +static int ush_ls_dir(const char *path, + int long_mode, + int recursive, + int print_header, + u64 depth) { + u64 count; + u64 i; + + if (depth > 16ULL) { + ush_writeln("ls: recursion depth limit reached"); + return 0; + } + + count = cleonos_sys_fs_child_count(path); + + if (print_header != 0) { + ush_write(path); + ush_writeln(":"); + } + + if (count == 0ULL) { + ush_writeln("(empty)"); + } + + for (i = 0ULL; i < count; i++) { + char name[CLEONOS_FS_NAME_MAX]; + char child_path[USH_PATH_MAX]; + u64 type; + u64 size = 0ULL; + + name[0] = '\0'; + + if (cleonos_sys_fs_get_child_name(path, i, name) == 0ULL) { + continue; + } + + if (ush_ls_join_path(path, name, child_path, (u64)sizeof(child_path)) == 0) { + continue; + } + + type = cleonos_sys_fs_stat_type(child_path); + + if (type == 1ULL) { + size = cleonos_sys_fs_stat_size(child_path); + } + + ush_ls_print_one(name, type, size, long_mode); + } + + if (recursive == 0) { + return 1; + } + + for (i = 0ULL; i < count; i++) { + char name[CLEONOS_FS_NAME_MAX]; + char child_path[USH_PATH_MAX]; + + name[0] = '\0'; + + if (cleonos_sys_fs_get_child_name(path, i, name) == 0ULL) { + continue; + } + + if (ush_ls_is_dot_entry(name) != 0) { + continue; + } + + if (ush_ls_join_path(path, name, child_path, (u64)sizeof(child_path)) == 0) { + continue; + } + + if (cleonos_sys_fs_stat_type(child_path) == 2ULL) { + ush_write_char('\n'); + (void)ush_ls_dir(child_path, long_mode, recursive, 1, depth + 1ULL); + } + } + + return 1; +} + +static int ush_cmd_ls(const ush_state *sh, const char *arg) { + char target[USH_PATH_MAX]; + char path[USH_PATH_MAX]; + u64 type; + int long_mode; + int recursive; + + if (ush_ls_parse_args(arg, &long_mode, &recursive, target, (u64)sizeof(target)) == 0) { + ush_writeln("ls: usage ls [-l] [-R] [path]"); + return 0; + } + + if (ush_resolve_path(sh, target, path, (u64)sizeof(path)) == 0) { + ush_writeln("ls: invalid path"); + return 0; + } + + type = cleonos_sys_fs_stat_type(path); + + if (type == 1ULL) { + u64 size = cleonos_sys_fs_stat_size(path); + ush_ls_print_one(ush_ls_basename(path), type, size, long_mode); + return 1; + } + + if (type != 2ULL) { + ush_writeln("ls: path not found"); + return 0; + } + + return ush_ls_dir(path, long_mode, recursive, recursive, 0ULL); +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + const char *arg = ""; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "ls") != 0) { + has_context = 1; + arg = ctx.arg; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_ls(&sh, arg); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/memstat_main.c b/cleonos/c/apps/memstat_main.c index e628e46..8824e00 100644 --- a/cleonos/c/apps/memstat_main.c +++ b/cleonos/c/apps/memstat_main.c @@ -1,6 +1,53 @@ -#include "shell/shell_internal.h" - -int cleonos_app_main(void) { - return ush_command_program_main("memstat"); +#include "cmd_runtime.h" +static int ush_cmd_memstat(void) { + ush_writeln("memstat (user ABI limited):"); + ush_print_kv_hex(" SERVICE_COUNT", cleonos_sys_service_count()); + ush_print_kv_hex(" SERVICE_READY_COUNT", cleonos_sys_service_ready_count()); + ush_print_kv_hex(" KELF_COUNT", cleonos_sys_kelf_count()); + ush_print_kv_hex(" KELF_RUNS", cleonos_sys_kelf_runs()); + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "memstat") != 0) { + has_context = 1; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_memstat(); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/mkdir_main.c b/cleonos/c/apps/mkdir_main.c index a857231..377833d 100644 --- a/cleonos/c/apps/mkdir_main.c +++ b/cleonos/c/apps/mkdir_main.c @@ -1,6 +1,72 @@ -#include "shell/shell_internal.h" +#include "cmd_runtime.h" +static int ush_cmd_mkdir(const ush_state *sh, const char *arg) { + char path[USH_PATH_MAX]; -int cleonos_app_main(void) { - return ush_command_program_main("mkdir"); + if (arg == (const char *)0 || arg[0] == '\0') { + ush_writeln("mkdir: directory path required"); + return 0; + } + + if (ush_resolve_path(sh, arg, path, (u64)sizeof(path)) == 0) { + ush_writeln("mkdir: invalid path"); + return 0; + } + + if (ush_path_is_under_temp(path) == 0) { + ush_writeln("mkdir: target must be under /temp"); + return 0; + } + + if (cleonos_sys_fs_mkdir(path) == 0ULL) { + ush_writeln("mkdir: failed"); + return 0; + } + + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + const char *arg = ""; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "mkdir") != 0) { + has_context = 1; + arg = ctx.arg; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_mkdir(&sh, arg); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/mv_main.c b/cleonos/c/apps/mv_main.c index 5e1a4cf..8968712 100644 --- a/cleonos/c/apps/mv_main.c +++ b/cleonos/c/apps/mv_main.c @@ -1,6 +1,129 @@ -#include "shell/shell_internal.h" +#include "cmd_runtime.h" +static int ush_copy_file(const char *src_path, const char *dst_path) { + static char copy_buf[USH_COPY_MAX]; + u64 src_type; + u64 src_size; + u64 got; -int cleonos_app_main(void) { - return ush_command_program_main("mv"); + src_type = cleonos_sys_fs_stat_type(src_path); + + if (src_type != 1ULL) { + ush_writeln("cp: source file not found"); + return 0; + } + + src_size = cleonos_sys_fs_stat_size(src_path); + + if (src_size == (u64)-1) { + ush_writeln("cp: failed to stat source"); + return 0; + } + + if (src_size > (u64)USH_COPY_MAX) { + ush_writeln("cp: source too large for user shell buffer"); + return 0; + } + + if (src_size == 0ULL) { + got = 0ULL; + } else { + got = cleonos_sys_fs_read(src_path, copy_buf, src_size); + + if (got == 0ULL || got != src_size) { + ush_writeln("cp: failed to read source"); + return 0; + } + } + + if (cleonos_sys_fs_write(dst_path, copy_buf, got) == 0ULL) { + ush_writeln("cp: failed to write destination"); + return 0; + } + + return 1; +} + +static int ush_cmd_mv(const ush_state *sh, const char *arg) { + char src_arg[USH_PATH_MAX]; + char dst_arg[USH_PATH_MAX]; + char src_path[USH_PATH_MAX]; + char dst_path[USH_PATH_MAX]; + + if (arg == (const char *)0 || arg[0] == '\0') { + ush_writeln("mv: usage mv "); + return 0; + } + + if (ush_split_two_args(arg, src_arg, (u64)sizeof(src_arg), dst_arg, (u64)sizeof(dst_arg)) == 0) { + ush_writeln("mv: usage mv "); + return 0; + } + + if (ush_resolve_path(sh, src_arg, src_path, (u64)sizeof(src_path)) == 0 || + ush_resolve_path(sh, dst_arg, dst_path, (u64)sizeof(dst_path)) == 0) { + ush_writeln("mv: invalid path"); + return 0; + } + + if (ush_path_is_under_temp(src_path) == 0 || ush_path_is_under_temp(dst_path) == 0) { + ush_writeln("mv: source and destination must be under /temp"); + return 0; + } + + if (ush_copy_file(src_path, dst_path) == 0) { + return 0; + } + + if (cleonos_sys_fs_remove(src_path) == 0ULL) { + ush_writeln("mv: source remove failed"); + return 0; + } + + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + const char *arg = ""; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "mv") != 0) { + has_context = 1; + arg = ctx.arg; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_mv(&sh, arg); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/pid_main.c b/cleonos/c/apps/pid_main.c index bab9422..1a9f17b 100644 --- a/cleonos/c/apps/pid_main.c +++ b/cleonos/c/apps/pid_main.c @@ -1,6 +1,49 @@ -#include "shell/shell_internal.h" - -int cleonos_app_main(void) { - return ush_command_program_main("pid"); +#include "cmd_runtime.h" +static int ush_cmd_pid(void) { + ush_print_kv_hex("PID", cleonos_sys_getpid()); + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "pid") != 0) { + has_context = 1; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_pid(); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/pwd_main.c b/cleonos/c/apps/pwd_main.c index b7d365c..e51db1d 100644 --- a/cleonos/c/apps/pwd_main.c +++ b/cleonos/c/apps/pwd_main.c @@ -1,6 +1,49 @@ -#include "shell/shell_internal.h" - -int cleonos_app_main(void) { - return ush_command_program_main("pwd"); +#include "cmd_runtime.h" +static int ush_cmd_pwd(const ush_state *sh) { + ush_writeln(sh->cwd); + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "pwd") != 0) { + has_context = 1; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_pwd(&sh); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/restart_main.c b/cleonos/c/apps/restart_main.c index 2c14d5f..07e6ce3 100644 --- a/cleonos/c/apps/restart_main.c +++ b/cleonos/c/apps/restart_main.c @@ -1,6 +1,50 @@ -#include "shell/shell_internal.h" - -int cleonos_app_main(void) { - return ush_command_program_main("restart"); +#include "cmd_runtime.h" +static int ush_cmd_restart(void) { + ush_writeln("restart: rebooting..."); + (void)cleonos_sys_restart(); + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "restart") != 0) { + has_context = 1; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_restart(); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/rm_main.c b/cleonos/c/apps/rm_main.c index 57161e0..66509c7 100644 --- a/cleonos/c/apps/rm_main.c +++ b/cleonos/c/apps/rm_main.c @@ -1,6 +1,72 @@ -#include "shell/shell_internal.h" +#include "cmd_runtime.h" +static int ush_cmd_rm(const ush_state *sh, const char *arg) { + char path[USH_PATH_MAX]; -int cleonos_app_main(void) { - return ush_command_program_main("rm"); + if (arg == (const char *)0 || arg[0] == '\0') { + ush_writeln("rm: path required"); + return 0; + } + + if (ush_resolve_path(sh, arg, path, (u64)sizeof(path)) == 0) { + ush_writeln("rm: invalid path"); + return 0; + } + + if (ush_path_is_under_temp(path) == 0) { + ush_writeln("rm: target must be under /temp"); + return 0; + } + + if (cleonos_sys_fs_remove(path) == 0ULL) { + ush_writeln("rm: failed (directory must be empty)"); + return 0; + } + + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + const char *arg = ""; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "rm") != 0) { + has_context = 1; + arg = ctx.arg; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_rm(&sh, arg); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/shell/cmd/ansi.inc b/cleonos/c/apps/shell/cmd/ansi.inc deleted file mode 100644 index e1678d1..0000000 --- a/cleonos/c/apps/shell/cmd/ansi.inc +++ /dev/null @@ -1,8 +0,0 @@ -static int ush_cmd_ansi(void) { - ush_writeln("\x1B[1;36mansi color demo\x1B[0m"); - ush_writeln(" \x1B[30mblack\x1B[0m \x1B[31mred\x1B[0m \x1B[32mgreen\x1B[0m \x1B[33myellow\x1B[0m"); - ush_writeln(" \x1B[34mblue\x1B[0m \x1B[35mmagenta\x1B[0m \x1B[36mcyan\x1B[0m \x1B[37mwhite\x1B[0m"); - ush_writeln(" \x1B[90mbright-black\x1B[0m \x1B[91mbright-red\x1B[0m \x1B[92mbright-green\x1B[0m \x1B[93mbright-yellow\x1B[0m"); - ush_writeln(" \x1B[94mbright-blue\x1B[0m \x1B[95mbright-magenta\x1B[0m \x1B[96mbright-cyan\x1B[0m \x1B[97mbright-white\x1B[0m"); - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/ansitest.inc b/cleonos/c/apps/shell/cmd/ansitest.inc deleted file mode 100644 index 3bb43e1..0000000 --- a/cleonos/c/apps/shell/cmd/ansitest.inc +++ /dev/null @@ -1,41 +0,0 @@ -static int ush_cmd_ansitest(void) { - u64 i; - - ush_writeln("\x1B[1;96mANSI test suite\x1B[0m"); - ush_writeln("styles: \x1B[1mbold\x1B[0m \x1B[7minverse\x1B[0m \x1B[4munderline\x1B[0m"); - ush_writeln("16-color demo:"); - (void)ush_cmd_ansi(); - - ush_writeln("256-color palette (0..255):"); - for (i = 0ULL; i < 256ULL; i++) { - ush_ansitest_emit_bg256(i); - if ((i % 32ULL) == 31ULL) { - ush_write_char('\n'); - } - } - ush_write_char('\n'); - - ush_writeln("truecolor demo:"); - ush_writeln(" \x1B[38;2;255;64;64mRGB(255,64,64)\x1B[0m \x1B[38;2;64;255;64mRGB(64,255,64)\x1B[0m \x1B[38;2;64;128;255mRGB(64,128,255)\x1B[0m"); - - ush_writeln("cursor control demo:"); - ush_write(" 0123456789"); - ush_write("\x1B[5D"); - ush_write("\x1B[93m\x1B[0m"); - ush_write_char('\n'); - - ush_write(" save"); - ush_write("\x1B[s"); - ush_write("...."); - ush_write("\x1B[u"); - ush_write("\x1B[92m\x1B[0m"); - ush_write_char('\n'); - - ush_writeln("erase-line demo:"); - ush_write(" left|right-to-clear"); - ush_write("\x1B[14D\x1B[K"); - ush_write_char('\n'); - - ush_writeln("ansitest done"); - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/ansitest_emit_bg256.inc b/cleonos/c/apps/shell/cmd/ansitest_emit_bg256.inc deleted file mode 100644 index 592a5bd..0000000 --- a/cleonos/c/apps/shell/cmd/ansitest_emit_bg256.inc +++ /dev/null @@ -1,43 +0,0 @@ -static void ush_ansitest_emit_bg256(u64 index) { - char num[4]; - char seq[24]; - u64 digits; - u64 p = 0ULL; - u64 i; - - if (index > 255U) { - index = 255U; - } - - digits = ush_ansitest_u64_to_dec(num, (u64)sizeof(num), index); - if (digits == 0ULL) { - return; - } - - seq[p++] = '\x1B'; - seq[p++] = '['; - seq[p++] = '4'; - seq[p++] = '8'; - seq[p++] = ';'; - seq[p++] = '5'; - seq[p++] = ';'; - - for (i = 0ULL; i < digits && p + 1ULL < (u64)sizeof(seq); i++) { - seq[p++] = num[i]; - } - - if (p + 7ULL >= (u64)sizeof(seq)) { - return; - } - - seq[p++] = 'm'; - seq[p++] = ' '; - seq[p++] = ' '; - seq[p++] = '\x1B'; - seq[p++] = '['; - seq[p++] = '0'; - seq[p++] = 'm'; - seq[p] = '\0'; - - ush_write(seq); -} diff --git a/cleonos/c/apps/shell/cmd/ansitest_u64_to_dec.inc b/cleonos/c/apps/shell/cmd/ansitest_u64_to_dec.inc deleted file mode 100644 index a1a85f7..0000000 --- a/cleonos/c/apps/shell/cmd/ansitest_u64_to_dec.inc +++ /dev/null @@ -1,36 +0,0 @@ -static u64 ush_ansitest_u64_to_dec(char *out, u64 out_size, u64 value) { - char rev[10]; - u64 digits = 0ULL; - u64 i; - - if (out == (char *)0 || out_size == 0ULL) { - return 0ULL; - } - - if (value == 0U) { - if (out_size < 2ULL) { - return 0ULL; - } - - out[0] = '0'; - out[1] = '\0'; - return 1ULL; - } - - while (value > 0U && digits < (u64)sizeof(rev)) { - rev[digits++] = (char)('0' + (value % 10U)); - value /= 10U; - } - - if (digits + 1ULL > out_size) { - out[0] = '\0'; - return 0ULL; - } - - for (i = 0ULL; i < digits; i++) { - out[i] = rev[digits - 1ULL - i]; - } - - out[digits] = '\0'; - return digits; -} diff --git a/cleonos/c/apps/shell/cmd/append.inc b/cleonos/c/apps/shell/cmd/append.inc deleted file mode 100644 index e99d07f..0000000 --- a/cleonos/c/apps/shell/cmd/append.inc +++ /dev/null @@ -1,44 +0,0 @@ -static int ush_cmd_append(const ush_state *sh, const char *arg) { - char path_arg[USH_PATH_MAX]; - char abs_path[USH_PATH_MAX]; - const char *payload = (const char *)0; - u64 payload_len; - - if (arg == (const char *)0 || arg[0] == '\0') { - ush_writeln("append: usage append "); - return 0; - } - - if (ush_split_first_and_rest(arg, path_arg, (u64)sizeof(path_arg), &payload) == 0) { - ush_writeln("append: usage append "); - return 0; - } - - if (ush_resolve_path(sh, path_arg, abs_path, (u64)sizeof(abs_path)) == 0) { - ush_writeln("append: invalid path"); - return 0; - } - - if (ush_path_is_under_temp(abs_path) == 0) { - ush_writeln("append: target must be under /temp"); - return 0; - } - - if (payload == (const char *)0 || payload[0] == '\0') { - if (ush_pipeline_stdin_text == (const char *)0) { - ush_writeln("append: usage append "); - return 0; - } - payload = ush_pipeline_stdin_text; - payload_len = ush_pipeline_stdin_len; - } else { - payload_len = ush_strlen(payload); - } - - if (cleonos_sys_fs_append(abs_path, payload, payload_len) == 0ULL) { - ush_writeln("append: failed"); - return 0; - } - - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/cat.inc b/cleonos/c/apps/shell/cmd/cat.inc deleted file mode 100644 index 3f053a7..0000000 --- a/cleonos/c/apps/shell/cmd/cat.inc +++ /dev/null @@ -1,59 +0,0 @@ -static int ush_cmd_cat(const ush_state *sh, const char *arg) { - char path[USH_PATH_MAX]; - char buf[USH_CAT_MAX + 1ULL]; - u64 size; - u64 req; - u64 got; - - if (arg == (const char *)0 || arg[0] == '\0') { - if (ush_pipeline_stdin_text != (const char *)0 && ush_pipeline_stdin_len > 0ULL) { - ush_write(ush_pipeline_stdin_text); - return 1; - } - - ush_writeln("cat: file path required"); - return 0; - } - - if (ush_resolve_path(sh, arg, path, (u64)sizeof(path)) == 0) { - ush_writeln("cat: invalid path"); - return 0; - } - - if (cleonos_sys_fs_stat_type(path) != 1ULL) { - ush_writeln("cat: file not found"); - return 0; - } - - size = cleonos_sys_fs_stat_size(path); - - if (size == (u64)-1) { - ush_writeln("cat: failed to stat file"); - return 0; - } - - if (size == 0ULL) { - return 1; - } - - req = (size < USH_CAT_MAX) ? size : USH_CAT_MAX; - got = cleonos_sys_fs_read(path, buf, req); - - if (got == 0ULL) { - ush_writeln("cat: read failed"); - return 0; - } - - if (got > USH_CAT_MAX) { - got = USH_CAT_MAX; - } - - buf[got] = '\0'; - ush_writeln(buf); - - if (size > got) { - ush_writeln("[cat] output truncated"); - } - - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/cd.inc b/cleonos/c/apps/shell/cmd/cd.inc deleted file mode 100644 index afbd005..0000000 --- a/cleonos/c/apps/shell/cmd/cd.inc +++ /dev/null @@ -1,21 +0,0 @@ -static int ush_cmd_cd(ush_state *sh, const char *arg) { - const char *target = arg; - char path[USH_PATH_MAX]; - - if (target == (const char *)0 || target[0] == '\0') { - target = "/"; - } - - if (ush_resolve_path(sh, target, path, (u64)sizeof(path)) == 0) { - ush_writeln("cd: invalid path"); - return 0; - } - - if (cleonos_sys_fs_stat_type(path) != 2ULL) { - ush_writeln("cd: directory not found"); - return 0; - } - - ush_copy(sh->cwd, (u64)sizeof(sh->cwd), path); - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/clear.inc b/cleonos/c/apps/shell/cmd/clear.inc deleted file mode 100644 index 5508b00..0000000 --- a/cleonos/c/apps/shell/cmd/clear.inc +++ /dev/null @@ -1,4 +0,0 @@ -static int ush_cmd_clear(void) { - ush_write("\x1B[2J\x1B[H"); - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/copy_file.inc b/cleonos/c/apps/shell/cmd/copy_file.inc deleted file mode 100644 index 43a0ce0..0000000 --- a/cleonos/c/apps/shell/cmd/copy_file.inc +++ /dev/null @@ -1,43 +0,0 @@ -static int ush_copy_file(const char *src_path, const char *dst_path) { - static char copy_buf[USH_COPY_MAX]; - u64 src_type; - u64 src_size; - u64 got; - - src_type = cleonos_sys_fs_stat_type(src_path); - - if (src_type != 1ULL) { - ush_writeln("cp: source file not found"); - return 0; - } - - src_size = cleonos_sys_fs_stat_size(src_path); - - if (src_size == (u64)-1) { - ush_writeln("cp: failed to stat source"); - return 0; - } - - if (src_size > (u64)USH_COPY_MAX) { - ush_writeln("cp: source too large for user shell buffer"); - return 0; - } - - if (src_size == 0ULL) { - got = 0ULL; - } else { - got = cleonos_sys_fs_read(src_path, copy_buf, src_size); - - if (got == 0ULL || got != src_size) { - ush_writeln("cp: failed to read source"); - return 0; - } - } - - if (cleonos_sys_fs_write(dst_path, copy_buf, got) == 0ULL) { - ush_writeln("cp: failed to write destination"); - return 0; - } - - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/cp.inc b/cleonos/c/apps/shell/cmd/cp.inc deleted file mode 100644 index e7c620b..0000000 --- a/cleonos/c/apps/shell/cmd/cp.inc +++ /dev/null @@ -1,29 +0,0 @@ -static int ush_cmd_cp(const ush_state *sh, const char *arg) { - char src_arg[USH_PATH_MAX]; - char dst_arg[USH_PATH_MAX]; - char src_path[USH_PATH_MAX]; - char dst_path[USH_PATH_MAX]; - - if (arg == (const char *)0 || arg[0] == '\0') { - ush_writeln("cp: usage cp "); - return 0; - } - - if (ush_split_two_args(arg, src_arg, (u64)sizeof(src_arg), dst_arg, (u64)sizeof(dst_arg)) == 0) { - ush_writeln("cp: usage cp "); - return 0; - } - - if (ush_resolve_path(sh, src_arg, src_path, (u64)sizeof(src_path)) == 0 || - ush_resolve_path(sh, dst_arg, dst_path, (u64)sizeof(dst_path)) == 0) { - ush_writeln("cp: invalid path"); - return 0; - } - - if (ush_path_is_under_temp(dst_path) == 0) { - ush_writeln("cp: destination must be under /temp"); - return 0; - } - - return ush_copy_file(src_path, dst_path); -} diff --git a/cleonos/c/apps/shell/cmd/dmesg.inc b/cleonos/c/apps/shell/cmd/dmesg.inc deleted file mode 100644 index 00fed5d..0000000 --- a/cleonos/c/apps/shell/cmd/dmesg.inc +++ /dev/null @@ -1,34 +0,0 @@ -static int ush_cmd_dmesg(const char *arg) { - u64 total = cleonos_sys_log_journal_count(); - u64 limit = USH_DMESG_DEFAULT; - u64 start; - u64 i; - - if (arg != (const char *)0 && arg[0] != '\0') { - if (ush_parse_u64_dec(arg, &limit) == 0 || limit == 0ULL) { - ush_writeln("dmesg: usage dmesg [positive_count]"); - return 0; - } - } - - if (total == 0ULL) { - ush_writeln("(journal empty)"); - return 1; - } - - if (limit > total) { - limit = total; - } - - start = total - limit; - - for (i = start; i < total; i++) { - char line[USH_DMESG_LINE_MAX]; - - if (cleonos_sys_log_journal_read(i, line, (u64)sizeof(line)) != 0ULL) { - ush_writeln(line); - } - } - - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/exec.inc b/cleonos/c/apps/shell/cmd/exec.inc deleted file mode 100644 index 47bda17..0000000 --- a/cleonos/c/apps/shell/cmd/exec.inc +++ /dev/null @@ -1,29 +0,0 @@ -static int ush_cmd_exec(const ush_state *sh, const char *arg) { - char path[USH_PATH_MAX]; - u64 status; - - if (ush_resolve_exec_path(sh, arg, path, (u64)sizeof(path)) == 0) { - ush_writeln("exec: invalid target"); - return 0; - } - - if (ush_path_is_under_system(path) != 0) { - ush_writeln("exec: /system/*.elf is kernel-mode (KELF), not user-exec"); - return 0; - } - - status = cleonos_sys_exec_path(path); - - if (status == (u64)-1) { - ush_writeln("exec: request failed"); - return 0; - } - - if (status == 0ULL) { - ush_writeln("exec: request accepted"); - return 1; - } - - ush_writeln("exec: returned non-zero status"); - return 0; -} diff --git a/cleonos/c/apps/shell/cmd/exit.inc b/cleonos/c/apps/shell/cmd/exit.inc deleted file mode 100644 index 2471c76..0000000 --- a/cleonos/c/apps/shell/cmd/exit.inc +++ /dev/null @@ -1,20 +0,0 @@ -static int ush_cmd_exit(ush_state *sh, const char *arg) { - u64 code = 0ULL; - - if (sh == (ush_state *)0) { - return 0; - } - - if (arg != (const char *)0 && arg[0] != '\0') { - if (ush_parse_u64_dec(arg, &code) == 0) { - ush_writeln("exit: usage exit [code]"); - return 0; - } - } - - sh->exit_requested = 1; - sh->exit_code = code; - (void)cleonos_sys_exit(code); - ush_writeln("exit: shell stopping"); - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/fastfetch.inc b/cleonos/c/apps/shell/cmd/fastfetch.inc deleted file mode 100644 index 315336a..0000000 --- a/cleonos/c/apps/shell/cmd/fastfetch.inc +++ /dev/null @@ -1,56 +0,0 @@ -static int ush_cmd_fastfetch(const char *arg) { - int plain = 0; - u64 tty_active; - u64 tty_count; - u64 exec_req; - u64 exec_ok; - - if (arg != (const char *)0 && arg[0] != '\0') { - if (ush_streq(arg, "--plain") != 0) { - plain = 1; - } else if (ush_streq(arg, "--help") != 0 || ush_streq(arg, "-h") != 0) { - ush_writeln("usage: fastfetch [--plain]"); - return 1; - } else { - ush_writeln("fastfetch: usage fastfetch [--plain]"); - return 0; - } - } - - tty_active = cleonos_sys_tty_active(); - tty_count = cleonos_sys_tty_count(); - exec_req = cleonos_sys_exec_request_count(); - exec_ok = cleonos_sys_exec_success_count(); - - ush_fastfetch_print_logo(plain); - ush_write_char('\n'); - - ush_fastfetch_print_text(plain, "OS", "CLeonOS x86_64"); - ush_fastfetch_print_text(plain, "Shell", "User Shell (/shell/shell.elf)"); - ush_fastfetch_print_u64(plain, "PID", cleonos_sys_getpid()); - ush_fastfetch_print_u64(plain, "UptimeTicks", cleonos_sys_timer_ticks()); - ush_fastfetch_print_u64(plain, "Tasks", cleonos_sys_task_count()); - ush_fastfetch_print_u64(plain, "Services", cleonos_sys_service_count()); - ush_fastfetch_print_u64(plain, "SvcReady", cleonos_sys_service_ready_count()); - ush_fastfetch_print_u64(plain, "CtxSwitches", cleonos_sys_context_switches()); - ush_fastfetch_print_u64(plain, "KELFApps", cleonos_sys_kelf_count()); - ush_fastfetch_print_u64(plain, "KELFRuns", cleonos_sys_kelf_runs()); - ush_fastfetch_print_u64(plain, "FSNodes", cleonos_sys_fs_node_count()); - ush_fastfetch_print_u64(plain, "RootChildren", cleonos_sys_fs_child_count("/")); - - ush_fastfetch_write_key(plain, "TTY"); - ush_fastfetch_write_u64_dec(tty_active); - ush_write(" / "); - ush_fastfetch_write_u64_dec(tty_count); - ush_write_char('\n'); - - ush_fastfetch_write_key(plain, "ExecSuccess"); - ush_fastfetch_write_u64_dec(exec_ok); - ush_write(" / "); - ush_fastfetch_write_u64_dec(exec_req); - ush_write_char('\n'); - - ush_fastfetch_print_u64(plain, "KbdBuffered", cleonos_sys_kbd_buffered()); - ush_fastfetch_print_palette(plain); - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/fastfetch_print_logo.inc b/cleonos/c/apps/shell/cmd/fastfetch_print_logo.inc deleted file mode 100644 index 27b4c77..0000000 --- a/cleonos/c/apps/shell/cmd/fastfetch_print_logo.inc +++ /dev/null @@ -1,25 +0,0 @@ -static void ush_fastfetch_print_logo(int plain) { - if (plain == 0) { - ush_writeln("\x1B[1;34m $$$$$$\\ $$\\ $$$$$$\\ $$$$$$\\ \x1B[0m"); - ush_writeln("\x1B[1;36m$$ __$$\\ $$ | $$ __$$\\ $$ __$$\\ \x1B[0m"); - ush_writeln("\x1B[1;32m$$ / \\__|$$ | $$$$$$\\ $$$$$$\\ $$$$$$$\\ $$ / $$ |$$ / \\__|\x1B[0m"); - ush_writeln("\x1B[1;33m$$ | $$ | $$ __$$\\ $$ __$$\\ $$ __$$\\ $$ | $$ |\\$$$$$$\\ \x1B[0m"); - ush_writeln("\x1B[1;31m$$ | $$ | $$$$$$$$ |$$ / $$ |$$ | $$ |$$ | $$ | \\____$$\\ \x1B[0m"); - ush_writeln("\x1B[1;35m$$ | $$\\ $$ | $$ ____|$$ | $$ |$$ | $$ |$$ | $$ |$$\\ $$ |\x1B[0m"); - ush_writeln("\x1B[1;94m\\$$$$$$ |$$$$$$$$\\ \\$$$$$$$\\ \\$$$$$$ |$$ | $$ | $$$$$$ |\\$$$$$$ |\x1B[0m"); - ush_writeln("\x1B[1;96m \\______/ \\________| \\_______| \\______/ \\__| \\__| \\______/ \\______/ \x1B[0m"); - ush_writeln(" "); - ush_writeln(" "); - } else { - ush_writeln(" $$$$$$\\ $$\\ $$$$$$\\ $$$$$$\\ "); - ush_writeln("$$ __$$\\ $$ | $$ __$$\\ $$ __$$\\ "); - ush_writeln("$$ / \\__|$$ | $$$$$$\\ $$$$$$\\ $$$$$$$\\ $$ / $$ |$$ / \\__|"); - ush_writeln("$$ | $$ | $$ __$$\\ $$ __$$\\ $$ __$$\\ $$ | $$ |\\$$$$$$\\ "); - ush_writeln("$$ | $$ | $$$$$$$$ |$$ / $$ |$$ | $$ |$$ | $$ | \\____$$\\ "); - ush_writeln("$$ | $$\\ $$ | $$ ____|$$ | $$ |$$ | $$ |$$ | $$ |$$\\ $$ |"); - ush_writeln("\\$$$$$$ |$$$$$$$$\\ \\$$$$$$$\\ \\$$$$$$ |$$ | $$ | $$$$$$ |\\$$$$$$ |"); - ush_writeln(" \\______/ \\________| \\_______| \\______/ \\__| \\__| \\______/ \\______/ "); - ush_writeln(" "); - ush_writeln(" "); - } -} diff --git a/cleonos/c/apps/shell/cmd/fastfetch_print_palette.inc b/cleonos/c/apps/shell/cmd/fastfetch_print_palette.inc deleted file mode 100644 index 3c518f3..0000000 --- a/cleonos/c/apps/shell/cmd/fastfetch_print_palette.inc +++ /dev/null @@ -1,14 +0,0 @@ -static void ush_fastfetch_print_palette(int plain) { - ush_fastfetch_write_key(plain, "Palette"); - - if (plain != 0) { - ush_writeln("ANSI16"); - return; - } - - ush_write("\x1B[40m \x1B[0m\x1B[41m \x1B[0m\x1B[42m \x1B[0m\x1B[43m \x1B[0m"); - ush_write("\x1B[44m \x1B[0m\x1B[45m \x1B[0m\x1B[46m \x1B[0m\x1B[47m \x1B[0m "); - ush_write("\x1B[100m \x1B[0m\x1B[101m \x1B[0m\x1B[102m \x1B[0m\x1B[103m \x1B[0m"); - ush_write("\x1B[104m \x1B[0m\x1B[105m \x1B[0m\x1B[106m \x1B[0m\x1B[107m \x1B[0m"); - ush_write_char('\n'); -} diff --git a/cleonos/c/apps/shell/cmd/fastfetch_print_text.inc b/cleonos/c/apps/shell/cmd/fastfetch_print_text.inc deleted file mode 100644 index d116f64..0000000 --- a/cleonos/c/apps/shell/cmd/fastfetch_print_text.inc +++ /dev/null @@ -1,4 +0,0 @@ -static void ush_fastfetch_print_text(int plain, const char *key, const char *value) { - ush_fastfetch_write_key(plain, key); - ush_writeln(value); -} diff --git a/cleonos/c/apps/shell/cmd/fastfetch_print_u64.inc b/cleonos/c/apps/shell/cmd/fastfetch_print_u64.inc deleted file mode 100644 index 66ff0eb..0000000 --- a/cleonos/c/apps/shell/cmd/fastfetch_print_u64.inc +++ /dev/null @@ -1,5 +0,0 @@ -static void ush_fastfetch_print_u64(int plain, const char *key, u64 value) { - ush_fastfetch_write_key(plain, key); - ush_fastfetch_write_u64_dec(value); - ush_write_char('\n'); -} diff --git a/cleonos/c/apps/shell/cmd/fastfetch_u64_to_dec.inc b/cleonos/c/apps/shell/cmd/fastfetch_u64_to_dec.inc deleted file mode 100644 index 1b1c68f..0000000 --- a/cleonos/c/apps/shell/cmd/fastfetch_u64_to_dec.inc +++ /dev/null @@ -1,34 +0,0 @@ -static u64 ush_fastfetch_u64_to_dec(char *out, u64 out_size, u64 value) { - char rev[32]; - u64 digits = 0ULL; - u64 i; - - if (out == (char *)0 || out_size == 0ULL) { - return 0ULL; - } - - if (value == 0ULL) { - if (out_size < 2ULL) { - return 0ULL; - } - out[0] = '0'; - out[1] = '\0'; - return 1ULL; - } - - while (value > 0ULL && digits < (u64)sizeof(rev)) { - rev[digits++] = (char)('0' + (value % 10ULL)); - value /= 10ULL; - } - - if (digits + 1ULL > out_size) { - out[0] = '\0'; - return 0ULL; - } - - for (i = 0ULL; i < digits; i++) { - out[i] = rev[digits - 1ULL - i]; - } - out[digits] = '\0'; - return digits; -} diff --git a/cleonos/c/apps/shell/cmd/fastfetch_write_key.inc b/cleonos/c/apps/shell/cmd/fastfetch_write_key.inc deleted file mode 100644 index 061a619..0000000 --- a/cleonos/c/apps/shell/cmd/fastfetch_write_key.inc +++ /dev/null @@ -1,11 +0,0 @@ -static void ush_fastfetch_write_key(int plain, const char *key) { - ush_write(" "); - if (plain == 0) { - ush_write("\x1B[1;96m"); - } - ush_write(key); - if (plain == 0) { - ush_write("\x1B[0m"); - } - ush_write(": "); -} diff --git a/cleonos/c/apps/shell/cmd/fastfetch_write_u64_dec.inc b/cleonos/c/apps/shell/cmd/fastfetch_write_u64_dec.inc deleted file mode 100644 index 71ad826..0000000 --- a/cleonos/c/apps/shell/cmd/fastfetch_write_u64_dec.inc +++ /dev/null @@ -1,10 +0,0 @@ -static void ush_fastfetch_write_u64_dec(u64 value) { - char text[32]; - - if (ush_fastfetch_u64_to_dec(text, (u64)sizeof(text), value) == 0ULL) { - ush_write("0"); - return; - } - - ush_write(text); -} diff --git a/cleonos/c/apps/shell/cmd/fsstat.inc b/cleonos/c/apps/shell/cmd/fsstat.inc deleted file mode 100644 index b49444a..0000000 --- a/cleonos/c/apps/shell/cmd/fsstat.inc +++ /dev/null @@ -1,10 +0,0 @@ -static int ush_cmd_fsstat(void) { - ush_writeln("fsstat:"); - ush_print_kv_hex(" NODE_COUNT", cleonos_sys_fs_node_count()); - ush_print_kv_hex(" ROOT_CHILDREN", cleonos_sys_fs_child_count("/")); - ush_print_kv_hex(" SYSTEM_CHILDREN", cleonos_sys_fs_child_count("/system")); - ush_print_kv_hex(" SHELL_CHILDREN", cleonos_sys_fs_child_count("/shell")); - ush_print_kv_hex(" TEMP_CHILDREN", cleonos_sys_fs_child_count("/temp")); - ush_print_kv_hex(" DRIVER_CHILDREN", cleonos_sys_fs_child_count("/driver")); - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/grep.inc b/cleonos/c/apps/shell/cmd/grep.inc deleted file mode 100644 index 6e3ab62..0000000 --- a/cleonos/c/apps/shell/cmd/grep.inc +++ /dev/null @@ -1,109 +0,0 @@ -static int ush_cmd_grep(const ush_state *sh, const char *arg) { - char first[USH_PATH_MAX]; - char second[USH_PATH_MAX]; - char third[USH_PATH_MAX]; - char path[USH_PATH_MAX]; - const char *rest = ""; - const char *rest2 = ""; - const char *pattern = (const char *)0; - const char *file_arg = (const char *)0; - const char *input = (const char *)0; - u64 input_len = 0ULL; - u64 size; - u64 got; - int with_line_number = 0; - static char file_buf[USH_COPY_MAX + 1U]; - - if (sh == (const ush_state *)0 || arg == (const char *)0 || arg[0] == '\0') { - ush_writeln("grep: usage grep [-n] [file]"); - return 0; - } - - if (ush_split_first_and_rest(arg, first, (u64)sizeof(first), &rest) == 0) { - ush_writeln("grep: usage grep [-n] [file]"); - return 0; - } - - if (ush_streq(first, "-n") != 0) { - with_line_number = 1; - - if (ush_split_first_and_rest(rest, second, (u64)sizeof(second), &rest2) == 0) { - ush_writeln("grep: usage grep [-n] [file]"); - return 0; - } - - pattern = second; - rest = rest2; - } else { - pattern = first; - } - - if (rest != (const char *)0 && rest[0] != '\0') { - if (ush_split_first_and_rest(rest, third, (u64)sizeof(third), &rest2) == 0) { - ush_writeln("grep: usage grep [-n] [file]"); - return 0; - } - - file_arg = third; - - if (rest2 != (const char *)0 && rest2[0] != '\0') { - ush_writeln("grep: usage grep [-n] [file]"); - return 0; - } - } - - if (pattern == (const char *)0 || pattern[0] == '\0') { - ush_writeln("grep: pattern required"); - return 0; - } - - if (file_arg != (const char *)0) { - if (ush_resolve_path(sh, file_arg, path, (u64)sizeof(path)) == 0) { - ush_writeln("grep: invalid path"); - return 0; - } - - if (cleonos_sys_fs_stat_type(path) != 1ULL) { - ush_writeln("grep: file not found"); - return 0; - } - - size = cleonos_sys_fs_stat_size(path); - - if (size == (u64)-1) { - ush_writeln("grep: failed to stat file"); - return 0; - } - - if (size > (u64)USH_COPY_MAX) { - ush_writeln("grep: file too large for user buffer"); - return 0; - } - - if (size == 0ULL) { - return 1; - } - - got = cleonos_sys_fs_read(path, file_buf, size); - - if (got == 0ULL || got != size) { - ush_writeln("grep: read failed"); - return 0; - } - - file_buf[got] = '\0'; - input = file_buf; - input_len = got; - } else { - if (ush_pipeline_stdin_text == (const char *)0) { - ush_writeln("grep: file path required (or pipeline input)"); - return 0; - } - - input = ush_pipeline_stdin_text; - input_len = ush_pipeline_stdin_len; - } - - (void)ush_grep_emit_matches(input, input_len, pattern, with_line_number); - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/grep_emit_matches.inc b/cleonos/c/apps/shell/cmd/grep_emit_matches.inc deleted file mode 100644 index 4e9b1b1..0000000 --- a/cleonos/c/apps/shell/cmd/grep_emit_matches.inc +++ /dev/null @@ -1,41 +0,0 @@ -static u64 ush_grep_emit_matches(const char *input, u64 input_len, const char *pattern, int with_line_number) { - u64 matches = 0ULL; - u64 line_no = 1ULL; - u64 start = 0ULL; - u64 i; - u64 pattern_len; - - if (input == (const char *)0 || pattern == (const char *)0) { - return 0ULL; - } - - pattern_len = ush_strlen(pattern); - - for (i = 0ULL; i <= input_len; i++) { - if (i == input_len || input[i] == '\n') { - u64 line_len = i - start; - - if (ush_grep_line_has_pattern(&input[start], line_len, pattern, pattern_len) != 0) { - u64 j; - - matches++; - - if (with_line_number != 0) { - ush_grep_write_u64_dec(line_no); - ush_write(":"); - } - - for (j = 0ULL; j < line_len; j++) { - ush_write_char(input[start + j]); - } - - ush_write_char('\n'); - } - - start = i + 1ULL; - line_no++; - } - } - - return matches; -} diff --git a/cleonos/c/apps/shell/cmd/grep_line_has_pattern.inc b/cleonos/c/apps/shell/cmd/grep_line_has_pattern.inc deleted file mode 100644 index b5906d7..0000000 --- a/cleonos/c/apps/shell/cmd/grep_line_has_pattern.inc +++ /dev/null @@ -1,29 +0,0 @@ -static int ush_grep_line_has_pattern(const char *line, u64 line_len, const char *pattern, u64 pattern_len) { - u64 i; - - if (line == (const char *)0 || pattern == (const char *)0) { - return 0; - } - - if (pattern_len == 0ULL) { - return 1; - } - - if (pattern_len > line_len) { - return 0; - } - - for (i = 0ULL; i + pattern_len <= line_len; i++) { - u64 j = 0ULL; - - while (j < pattern_len && line[i + j] == pattern[j]) { - j++; - } - - if (j == pattern_len) { - return 1; - } - } - - return 0; -} diff --git a/cleonos/c/apps/shell/cmd/grep_write_u64_dec.inc b/cleonos/c/apps/shell/cmd/grep_write_u64_dec.inc deleted file mode 100644 index 55f884b..0000000 --- a/cleonos/c/apps/shell/cmd/grep_write_u64_dec.inc +++ /dev/null @@ -1,19 +0,0 @@ -static void ush_grep_write_u64_dec(u64 value) { - char tmp[32]; - u64 len = 0ULL; - - if (value == 0ULL) { - ush_write_char('0'); - return; - } - - while (value > 0ULL && len < (u64)sizeof(tmp)) { - tmp[len++] = (char)('0' + (value % 10ULL)); - value /= 10ULL; - } - - while (len > 0ULL) { - len--; - ush_write_char(tmp[len]); - } -} diff --git a/cleonos/c/apps/shell/cmd/help.inc b/cleonos/c/apps/shell/cmd/help.inc deleted file mode 100644 index 044e18d..0000000 --- a/cleonos/c/apps/shell/cmd/help.inc +++ /dev/null @@ -1,36 +0,0 @@ -static int ush_cmd_help(void) { - ush_writeln("commands:"); - ush_writeln(" help"); - ush_writeln(" ls [-l] [-R] [path]"); - ush_writeln(" cat [file] (reads pipeline input when file omitted)"); - ush_writeln(" grep [-n] [file]"); - ush_writeln(" pwd"); - ush_writeln(" cd [dir]"); - ush_writeln(" exec|run "); - ush_writeln(" clear"); - ush_writeln(" ansi / ansitest / color"); - ush_writeln(" fastfetch [--plain]"); - ush_writeln(" memstat / fsstat / taskstat / userstat / shstat / stats"); - ush_writeln(" tty [index]"); - ush_writeln(" dmesg [n]"); - ush_writeln(" kbdstat"); - ush_writeln(" mkdir (/temp only)"); - ush_writeln(" touch (/temp only)"); - ush_writeln(" write (/temp only, or from pipeline)"); - ush_writeln(" append (/temp only, or from pipeline)"); - ush_writeln(" cp (dst /temp only)"); - ush_writeln(" mv (/temp only)"); - ush_writeln(" rm (/temp only)"); - ush_writeln(" pid"); - ush_writeln(" spawn "); - ush_writeln(" wait "); - ush_writeln(" sleep "); - ush_writeln(" yield"); - ush_writeln(" shutdown / restart"); - ush_writeln(" exit [code]"); - ush_writeln(" rusttest / panic / elfloader (kernel shell only)"); - ush_writeln("pipeline/redirection: cmd1 | cmd2 | cmd3 > /temp/out.txt"); - ush_writeln("redirection append: cmd >> /temp/out.txt"); - ush_writeln("edit keys: Left/Right, Home/End, Up/Down history"); - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/kbdstat.inc b/cleonos/c/apps/shell/cmd/kbdstat.inc deleted file mode 100644 index 9e90150..0000000 --- a/cleonos/c/apps/shell/cmd/kbdstat.inc +++ /dev/null @@ -1,9 +0,0 @@ -static int ush_cmd_kbdstat(void) { - ush_writeln("kbdstat:"); - ush_print_kv_hex(" BUFFERED", cleonos_sys_kbd_buffered()); - ush_print_kv_hex(" PUSHED", cleonos_sys_kbd_pushed()); - ush_print_kv_hex(" POPPED", cleonos_sys_kbd_popped()); - ush_print_kv_hex(" DROPPED", cleonos_sys_kbd_dropped()); - ush_print_kv_hex(" HOTKEY_SWITCHES", cleonos_sys_kbd_hotkey_switches()); - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/ls.inc b/cleonos/c/apps/shell/cmd/ls.inc deleted file mode 100644 index 376d1f8..0000000 --- a/cleonos/c/apps/shell/cmd/ls.inc +++ /dev/null @@ -1,32 +0,0 @@ -static int ush_cmd_ls(const ush_state *sh, const char *arg) { - char target[USH_PATH_MAX]; - char path[USH_PATH_MAX]; - u64 type; - int long_mode; - int recursive; - - if (ush_ls_parse_args(arg, &long_mode, &recursive, target, (u64)sizeof(target)) == 0) { - ush_writeln("ls: usage ls [-l] [-R] [path]"); - return 0; - } - - if (ush_resolve_path(sh, target, path, (u64)sizeof(path)) == 0) { - ush_writeln("ls: invalid path"); - return 0; - } - - type = cleonos_sys_fs_stat_type(path); - - if (type == 1ULL) { - u64 size = cleonos_sys_fs_stat_size(path); - ush_ls_print_one(ush_ls_basename(path), type, size, long_mode); - return 1; - } - - if (type != 2ULL) { - ush_writeln("ls: path not found"); - return 0; - } - - return ush_ls_dir(path, long_mode, recursive, recursive, 0ULL); -} diff --git a/cleonos/c/apps/shell/cmd/ls_basename.inc b/cleonos/c/apps/shell/cmd/ls_basename.inc deleted file mode 100644 index 928f6c1..0000000 --- a/cleonos/c/apps/shell/cmd/ls_basename.inc +++ /dev/null @@ -1,18 +0,0 @@ -static const char *ush_ls_basename(const char *path) { - const char *name = path; - u64 i = 0ULL; - - if (path == (const char *)0 || path[0] == '\0') { - return ""; - } - - while (path[i] != '\0') { - if (path[i] == '/' && path[i + 1ULL] != '\0') { - name = &path[i + 1ULL]; - } - - i++; - } - - return name; -} diff --git a/cleonos/c/apps/shell/cmd/ls_dir.inc b/cleonos/c/apps/shell/cmd/ls_dir.inc deleted file mode 100644 index d3cd2ba..0000000 --- a/cleonos/c/apps/shell/cmd/ls_dir.inc +++ /dev/null @@ -1,79 +0,0 @@ -static int ush_ls_dir(const char *path, - int long_mode, - int recursive, - int print_header, - u64 depth) { - u64 count; - u64 i; - - if (depth > 16ULL) { - ush_writeln("ls: recursion depth limit reached"); - return 0; - } - - count = cleonos_sys_fs_child_count(path); - - if (print_header != 0) { - ush_write(path); - ush_writeln(":"); - } - - if (count == 0ULL) { - ush_writeln("(empty)"); - } - - for (i = 0ULL; i < count; i++) { - char name[CLEONOS_FS_NAME_MAX]; - char child_path[USH_PATH_MAX]; - u64 type; - u64 size = 0ULL; - - name[0] = '\0'; - - if (cleonos_sys_fs_get_child_name(path, i, name) == 0ULL) { - continue; - } - - if (ush_ls_join_path(path, name, child_path, (u64)sizeof(child_path)) == 0) { - continue; - } - - type = cleonos_sys_fs_stat_type(child_path); - - if (type == 1ULL) { - size = cleonos_sys_fs_stat_size(child_path); - } - - ush_ls_print_one(name, type, size, long_mode); - } - - if (recursive == 0) { - return 1; - } - - for (i = 0ULL; i < count; i++) { - char name[CLEONOS_FS_NAME_MAX]; - char child_path[USH_PATH_MAX]; - - name[0] = '\0'; - - if (cleonos_sys_fs_get_child_name(path, i, name) == 0ULL) { - continue; - } - - if (ush_ls_is_dot_entry(name) != 0) { - continue; - } - - if (ush_ls_join_path(path, name, child_path, (u64)sizeof(child_path)) == 0) { - continue; - } - - if (cleonos_sys_fs_stat_type(child_path) == 2ULL) { - ush_write_char('\n'); - (void)ush_ls_dir(child_path, long_mode, recursive, 1, depth + 1ULL); - } - } - - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/ls_is_dot_entry.inc b/cleonos/c/apps/shell/cmd/ls_is_dot_entry.inc deleted file mode 100644 index c5745e1..0000000 --- a/cleonos/c/apps/shell/cmd/ls_is_dot_entry.inc +++ /dev/null @@ -1,15 +0,0 @@ -static int ush_ls_is_dot_entry(const char *name) { - if (name == (const char *)0) { - return 0; - } - - if (name[0] == '.' && name[1] == '\0') { - return 1; - } - - if (name[0] == '.' && name[1] == '.' && name[2] == '\0') { - return 1; - } - - return 0; -} diff --git a/cleonos/c/apps/shell/cmd/ls_join_path.inc b/cleonos/c/apps/shell/cmd/ls_join_path.inc deleted file mode 100644 index 487a89a..0000000 --- a/cleonos/c/apps/shell/cmd/ls_join_path.inc +++ /dev/null @@ -1,43 +0,0 @@ -static int ush_ls_join_path(const char *dir_path, const char *name, char *out_path, u64 out_size) { - u64 p = 0ULL; - u64 i; - - if (dir_path == (const char *)0 || name == (const char *)0 || out_path == (char *)0 || out_size == 0ULL) { - return 0; - } - - if (dir_path[0] == '/' && dir_path[1] == '\0') { - if (out_size < 2ULL) { - return 0; - } - - out_path[p++] = '/'; - } else { - for (i = 0ULL; dir_path[i] != '\0'; i++) { - if (p + 1ULL >= out_size) { - return 0; - } - - out_path[p++] = dir_path[i]; - } - - if (p == 0ULL || out_path[p - 1ULL] != '/') { - if (p + 1ULL >= out_size) { - return 0; - } - - out_path[p++] = '/'; - } - } - - for (i = 0ULL; name[i] != '\0'; i++) { - if (p + 1ULL >= out_size) { - return 0; - } - - out_path[p++] = name[i]; - } - - out_path[p] = '\0'; - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/ls_parse_args.inc b/cleonos/c/apps/shell/cmd/ls_parse_args.inc deleted file mode 100644 index 36256e0..0000000 --- a/cleonos/c/apps/shell/cmd/ls_parse_args.inc +++ /dev/null @@ -1,70 +0,0 @@ -static int ush_ls_parse_args(const char *arg, - int *out_long_mode, - int *out_recursive, - char *out_target, - u64 out_target_size) { - char token[USH_PATH_MAX]; - u64 i = 0ULL; - int path_set = 0; - - if (out_long_mode == (int *)0 || - out_recursive == (int *)0 || - out_target == (char *)0 || - out_target_size == 0ULL) { - return 0; - } - - *out_long_mode = 0; - *out_recursive = 0; - ush_copy(out_target, out_target_size, "."); - - if (arg == (const char *)0 || arg[0] == '\0') { - return 1; - } - - while (arg[i] != '\0') { - u64 p = 0ULL; - u64 j; - - while (arg[i] != '\0' && ush_is_space(arg[i]) != 0) { - i++; - } - - if (arg[i] == '\0') { - break; - } - - while (arg[i] != '\0' && ush_is_space(arg[i]) == 0) { - if (p + 1ULL < (u64)sizeof(token)) { - token[p++] = arg[i]; - } - - i++; - } - - token[p] = '\0'; - - if (token[0] == '-' && token[1] != '\0') { - for (j = 1ULL; token[j] != '\0'; j++) { - if (token[j] == 'l') { - *out_long_mode = 1; - } else if (token[j] == 'R') { - *out_recursive = 1; - } else { - return 0; - } - } - - continue; - } - - if (path_set != 0) { - return 0; - } - - ush_copy(out_target, out_target_size, token); - path_set = 1; - } - - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/ls_print_one.inc b/cleonos/c/apps/shell/cmd/ls_print_one.inc deleted file mode 100644 index 27dd73f..0000000 --- a/cleonos/c/apps/shell/cmd/ls_print_one.inc +++ /dev/null @@ -1,27 +0,0 @@ -static void ush_ls_print_one(const char *name, u64 type, u64 size, int long_mode) { - if (long_mode == 0) { - ush_writeln(name); - return; - } - - if (type == 2ULL) { - ush_write("d "); - } else if (type == 1ULL) { - ush_write("f "); - } else { - ush_write("? "); - } - - ush_write(name); - - if (type == 1ULL) { - ush_write(" size="); - ush_write_hex_u64(size); - } else if (type == 2ULL) { - ush_write(" "); - } else { - ush_write(" "); - } - - ush_write_char('\n'); -} diff --git a/cleonos/c/apps/shell/cmd/memstat.inc b/cleonos/c/apps/shell/cmd/memstat.inc deleted file mode 100644 index 10f38d3..0000000 --- a/cleonos/c/apps/shell/cmd/memstat.inc +++ /dev/null @@ -1,8 +0,0 @@ -static int ush_cmd_memstat(void) { - ush_writeln("memstat (user ABI limited):"); - ush_print_kv_hex(" SERVICE_COUNT", cleonos_sys_service_count()); - ush_print_kv_hex(" SERVICE_READY_COUNT", cleonos_sys_service_ready_count()); - ush_print_kv_hex(" KELF_COUNT", cleonos_sys_kelf_count()); - ush_print_kv_hex(" KELF_RUNS", cleonos_sys_kelf_runs()); - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/mkdir.inc b/cleonos/c/apps/shell/cmd/mkdir.inc deleted file mode 100644 index 211e464..0000000 --- a/cleonos/c/apps/shell/cmd/mkdir.inc +++ /dev/null @@ -1,25 +0,0 @@ -static int ush_cmd_mkdir(const ush_state *sh, const char *arg) { - char path[USH_PATH_MAX]; - - if (arg == (const char *)0 || arg[0] == '\0') { - ush_writeln("mkdir: directory path required"); - return 0; - } - - if (ush_resolve_path(sh, arg, path, (u64)sizeof(path)) == 0) { - ush_writeln("mkdir: invalid path"); - return 0; - } - - if (ush_path_is_under_temp(path) == 0) { - ush_writeln("mkdir: target must be under /temp"); - return 0; - } - - if (cleonos_sys_fs_mkdir(path) == 0ULL) { - ush_writeln("mkdir: failed"); - return 0; - } - - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/mv.inc b/cleonos/c/apps/shell/cmd/mv.inc deleted file mode 100644 index 302c13e..0000000 --- a/cleonos/c/apps/shell/cmd/mv.inc +++ /dev/null @@ -1,38 +0,0 @@ -static int ush_cmd_mv(const ush_state *sh, const char *arg) { - char src_arg[USH_PATH_MAX]; - char dst_arg[USH_PATH_MAX]; - char src_path[USH_PATH_MAX]; - char dst_path[USH_PATH_MAX]; - - if (arg == (const char *)0 || arg[0] == '\0') { - ush_writeln("mv: usage mv "); - return 0; - } - - if (ush_split_two_args(arg, src_arg, (u64)sizeof(src_arg), dst_arg, (u64)sizeof(dst_arg)) == 0) { - ush_writeln("mv: usage mv "); - return 0; - } - - if (ush_resolve_path(sh, src_arg, src_path, (u64)sizeof(src_path)) == 0 || - ush_resolve_path(sh, dst_arg, dst_path, (u64)sizeof(dst_path)) == 0) { - ush_writeln("mv: invalid path"); - return 0; - } - - if (ush_path_is_under_temp(src_path) == 0 || ush_path_is_under_temp(dst_path) == 0) { - ush_writeln("mv: source and destination must be under /temp"); - return 0; - } - - if (ush_copy_file(src_path, dst_path) == 0) { - return 0; - } - - if (cleonos_sys_fs_remove(src_path) == 0ULL) { - ush_writeln("mv: source remove failed"); - return 0; - } - - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/not_supported.inc b/cleonos/c/apps/shell/cmd/not_supported.inc deleted file mode 100644 index e3869e7..0000000 --- a/cleonos/c/apps/shell/cmd/not_supported.inc +++ /dev/null @@ -1,6 +0,0 @@ -static int ush_cmd_not_supported(const char *name, const char *why) { - ush_write(name); - ush_write(": "); - ush_writeln(why); - return 0; -} diff --git a/cleonos/c/apps/shell/cmd/pid.inc b/cleonos/c/apps/shell/cmd/pid.inc deleted file mode 100644 index 8e70300..0000000 --- a/cleonos/c/apps/shell/cmd/pid.inc +++ /dev/null @@ -1,4 +0,0 @@ -static int ush_cmd_pid(void) { - ush_print_kv_hex("PID", cleonos_sys_getpid()); - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/pwd.inc b/cleonos/c/apps/shell/cmd/pwd.inc deleted file mode 100644 index ae7f82c..0000000 --- a/cleonos/c/apps/shell/cmd/pwd.inc +++ /dev/null @@ -1,4 +0,0 @@ -static int ush_cmd_pwd(const ush_state *sh) { - ush_writeln(sh->cwd); - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/restart.inc b/cleonos/c/apps/shell/cmd/restart.inc deleted file mode 100644 index 7a1cc58..0000000 --- a/cleonos/c/apps/shell/cmd/restart.inc +++ /dev/null @@ -1,5 +0,0 @@ -static int ush_cmd_restart(void) { - ush_writeln("restart: rebooting..."); - (void)cleonos_sys_restart(); - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/rm.inc b/cleonos/c/apps/shell/cmd/rm.inc deleted file mode 100644 index ca18372..0000000 --- a/cleonos/c/apps/shell/cmd/rm.inc +++ /dev/null @@ -1,25 +0,0 @@ -static int ush_cmd_rm(const ush_state *sh, const char *arg) { - char path[USH_PATH_MAX]; - - if (arg == (const char *)0 || arg[0] == '\0') { - ush_writeln("rm: path required"); - return 0; - } - - if (ush_resolve_path(sh, arg, path, (u64)sizeof(path)) == 0) { - ush_writeln("rm: invalid path"); - return 0; - } - - if (ush_path_is_under_temp(path) == 0) { - ush_writeln("rm: target must be under /temp"); - return 0; - } - - if (cleonos_sys_fs_remove(path) == 0ULL) { - ush_writeln("rm: failed (directory must be empty)"); - return 0; - } - - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/shstat.inc b/cleonos/c/apps/shell/cmd/shstat.inc deleted file mode 100644 index addd2c6..0000000 --- a/cleonos/c/apps/shell/cmd/shstat.inc +++ /dev/null @@ -1,10 +0,0 @@ -static int ush_cmd_shstat(const ush_state *sh) { - ush_writeln("shstat:"); - ush_print_kv_hex(" CMD_TOTAL", sh->cmd_total); - ush_print_kv_hex(" CMD_OK", sh->cmd_ok); - ush_print_kv_hex(" CMD_FAIL", sh->cmd_fail); - ush_print_kv_hex(" CMD_UNKNOWN", sh->cmd_unknown); - ush_print_kv_hex(" EXIT_REQUESTED", (sh->exit_requested != 0) ? 1ULL : 0ULL); - ush_print_kv_hex(" EXIT_CODE", sh->exit_code); - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/shutdown.inc b/cleonos/c/apps/shell/cmd/shutdown.inc deleted file mode 100644 index 4ea1c2c..0000000 --- a/cleonos/c/apps/shell/cmd/shutdown.inc +++ /dev/null @@ -1,5 +0,0 @@ -static int ush_cmd_shutdown(void) { - ush_writeln("shutdown: powering off..."); - (void)cleonos_sys_shutdown(); - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/sleep.inc b/cleonos/c/apps/shell/cmd/sleep.inc deleted file mode 100644 index 5aa19b7..0000000 --- a/cleonos/c/apps/shell/cmd/sleep.inc +++ /dev/null @@ -1,18 +0,0 @@ -static int ush_cmd_sleep(const char *arg) { - u64 ticks; - u64 elapsed; - - if (arg == (const char *)0 || arg[0] == '\0') { - ush_writeln("sleep: usage sleep "); - return 0; - } - - if (ush_parse_u64_dec(arg, &ticks) == 0) { - ush_writeln("sleep: invalid ticks"); - return 0; - } - - elapsed = cleonos_sys_sleep_ticks(ticks); - ush_print_kv_hex("SLEPT_TICKS", elapsed); - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/spawn.inc b/cleonos/c/apps/shell/cmd/spawn.inc deleted file mode 100644 index e8dcaaa..0000000 --- a/cleonos/c/apps/shell/cmd/spawn.inc +++ /dev/null @@ -1,25 +0,0 @@ -static int ush_cmd_spawn(const ush_state *sh, const char *arg) { - char path[USH_PATH_MAX]; - u64 pid; - - if (ush_resolve_exec_path(sh, arg, path, (u64)sizeof(path)) == 0) { - ush_writeln("spawn: invalid target"); - return 0; - } - - if (ush_path_is_under_system(path) != 0) { - ush_writeln("spawn: /system/*.elf is kernel-mode (KELF), not user-exec"); - return 0; - } - - pid = cleonos_sys_spawn_path(path); - - if (pid == (u64)-1) { - ush_writeln("spawn: request failed"); - return 0; - } - - ush_writeln("spawn: completed"); - ush_print_kv_hex(" PID", pid); - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/stats.inc b/cleonos/c/apps/shell/cmd/stats.inc deleted file mode 100644 index 1bc8f21..0000000 --- a/cleonos/c/apps/shell/cmd/stats.inc +++ /dev/null @@ -1,9 +0,0 @@ -static int ush_cmd_stats(const ush_state *sh) { - (void)ush_cmd_memstat(); - (void)ush_cmd_fsstat(); - (void)ush_cmd_taskstat(); - (void)ush_cmd_userstat(); - (void)ush_cmd_kbdstat(); - (void)ush_cmd_shstat(sh); - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/taskstat.inc b/cleonos/c/apps/shell/cmd/taskstat.inc deleted file mode 100644 index 3615ae1..0000000 --- a/cleonos/c/apps/shell/cmd/taskstat.inc +++ /dev/null @@ -1,8 +0,0 @@ -static int ush_cmd_taskstat(void) { - ush_writeln("taskstat:"); - ush_print_kv_hex(" TASK_COUNT", cleonos_sys_task_count()); - ush_print_kv_hex(" CURRENT_TASK", cleonos_syscall(CLEONOS_SYSCALL_CUR_TASK, 0ULL, 0ULL, 0ULL)); - ush_print_kv_hex(" TIMER_TICKS", cleonos_sys_timer_ticks()); - ush_print_kv_hex(" CONTEXT_SWITCHES", cleonos_sys_context_switches()); - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/touch.inc b/cleonos/c/apps/shell/cmd/touch.inc deleted file mode 100644 index 4e5866d..0000000 --- a/cleonos/c/apps/shell/cmd/touch.inc +++ /dev/null @@ -1,26 +0,0 @@ -static int ush_cmd_touch(const ush_state *sh, const char *arg) { - static const char empty_data[1] = {'\0'}; - char path[USH_PATH_MAX]; - - if (arg == (const char *)0 || arg[0] == '\0') { - ush_writeln("touch: file path required"); - return 0; - } - - if (ush_resolve_path(sh, arg, path, (u64)sizeof(path)) == 0) { - ush_writeln("touch: invalid path"); - return 0; - } - - if (ush_path_is_under_temp(path) == 0) { - ush_writeln("touch: target must be under /temp"); - return 0; - } - - if (cleonos_sys_fs_write(path, empty_data, 0ULL) == 0ULL) { - ush_writeln("touch: failed"); - return 0; - } - - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/tty.inc b/cleonos/c/apps/shell/cmd/tty.inc deleted file mode 100644 index 09388d0..0000000 --- a/cleonos/c/apps/shell/cmd/tty.inc +++ /dev/null @@ -1,33 +0,0 @@ -static int ush_cmd_tty(const char *arg) { - u64 tty_count = cleonos_sys_tty_count(); - u64 active = cleonos_sys_tty_active(); - - if (arg == (const char *)0 || arg[0] == '\0') { - ush_print_kv_hex("TTY_COUNT", tty_count); - ush_print_kv_hex("TTY_ACTIVE", active); - return 1; - } - - { - u64 idx; - - if (ush_parse_u64_dec(arg, &idx) == 0) { - ush_writeln("tty: usage tty [index]"); - return 0; - } - - if (idx >= tty_count) { - ush_writeln("tty: index out of range"); - return 0; - } - - if (cleonos_sys_tty_switch(idx) == (u64)-1) { - ush_writeln("tty: switch failed"); - return 0; - } - - ush_writeln("tty: switched"); - ush_print_kv_hex("TTY_ACTIVE", cleonos_sys_tty_active()); - return 1; - } -} diff --git a/cleonos/c/apps/shell/cmd/userstat.inc b/cleonos/c/apps/shell/cmd/userstat.inc deleted file mode 100644 index 0c8b5fa..0000000 --- a/cleonos/c/apps/shell/cmd/userstat.inc +++ /dev/null @@ -1,13 +0,0 @@ -static int ush_cmd_userstat(void) { - ush_writeln("userstat:"); - ush_print_kv_hex(" USER_SHELL_READY", cleonos_sys_user_shell_ready()); - ush_print_kv_hex(" USER_EXEC_REQUESTED", cleonos_sys_user_exec_requested()); - ush_print_kv_hex(" USER_LAUNCH_TRIES", cleonos_sys_user_launch_tries()); - ush_print_kv_hex(" USER_LAUNCH_OK", cleonos_sys_user_launch_ok()); - ush_print_kv_hex(" USER_LAUNCH_FAIL", cleonos_sys_user_launch_fail()); - ush_print_kv_hex(" EXEC_REQUESTS", cleonos_sys_exec_request_count()); - ush_print_kv_hex(" EXEC_SUCCESS", cleonos_sys_exec_success_count()); - ush_print_kv_hex(" TTY_COUNT", cleonos_sys_tty_count()); - ush_print_kv_hex(" TTY_ACTIVE", cleonos_sys_tty_active()); - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/wait.inc b/cleonos/c/apps/shell/cmd/wait.inc deleted file mode 100644 index 185a9d7..0000000 --- a/cleonos/c/apps/shell/cmd/wait.inc +++ /dev/null @@ -1,31 +0,0 @@ -static int ush_cmd_wait(const char *arg) { - u64 pid; - u64 status = (u64)-1; - u64 wait_ret; - - if (arg == (const char *)0 || arg[0] == '\0') { - ush_writeln("wait: usage wait "); - return 0; - } - - if (ush_parse_u64_dec(arg, &pid) == 0) { - ush_writeln("wait: invalid pid"); - return 0; - } - - wait_ret = cleonos_sys_wait_pid(pid, &status); - - if (wait_ret == (u64)-1) { - ush_writeln("wait: pid not found"); - return 0; - } - - if (wait_ret == 0ULL) { - ush_writeln("wait: still running"); - return 1; - } - - ush_writeln("wait: exited"); - ush_print_kv_hex(" STATUS", status); - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/write.inc b/cleonos/c/apps/shell/cmd/write.inc deleted file mode 100644 index fb0c973..0000000 --- a/cleonos/c/apps/shell/cmd/write.inc +++ /dev/null @@ -1,44 +0,0 @@ -static int ush_cmd_write(const ush_state *sh, const char *arg) { - char path_arg[USH_PATH_MAX]; - char abs_path[USH_PATH_MAX]; - const char *payload = (const char *)0; - u64 payload_len; - - if (arg == (const char *)0 || arg[0] == '\0') { - ush_writeln("write: usage write "); - return 0; - } - - if (ush_split_first_and_rest(arg, path_arg, (u64)sizeof(path_arg), &payload) == 0) { - ush_writeln("write: usage write "); - return 0; - } - - if (ush_resolve_path(sh, path_arg, abs_path, (u64)sizeof(abs_path)) == 0) { - ush_writeln("write: invalid path"); - return 0; - } - - if (ush_path_is_under_temp(abs_path) == 0) { - ush_writeln("write: target must be under /temp"); - return 0; - } - - if (payload == (const char *)0 || payload[0] == '\0') { - if (ush_pipeline_stdin_text == (const char *)0) { - ush_writeln("write: usage write "); - return 0; - } - payload = ush_pipeline_stdin_text; - payload_len = ush_pipeline_stdin_len; - } else { - payload_len = ush_strlen(payload); - } - - if (cleonos_sys_fs_write(abs_path, payload, payload_len) == 0ULL) { - ush_writeln("write: failed"); - return 0; - } - - return 1; -} diff --git a/cleonos/c/apps/shell/cmd/yield.inc b/cleonos/c/apps/shell/cmd/yield.inc deleted file mode 100644 index f930349..0000000 --- a/cleonos/c/apps/shell/cmd/yield.inc +++ /dev/null @@ -1,4 +0,0 @@ -static int ush_cmd_yield(void) { - ush_print_kv_hex("YIELD_TICK", cleonos_sys_yield()); - return 1; -} diff --git a/cleonos/c/apps/shell/shell_cmd.c b/cleonos/c/apps/shell/shell_cmd.c index d176c2d..76be2e9 100644 --- a/cleonos/c/apps/shell/shell_cmd.c +++ b/cleonos/c/apps/shell/shell_cmd.c @@ -123,113 +123,1508 @@ static int ush_split_two_args(const char *arg, return (out_first[0] != '\0' && out_second[0] != '\0') ? 1 : 0; } -#include "cmd/help.inc" +static int ush_cmd_help(void) { + ush_writeln("commands:"); + ush_writeln(" help"); + ush_writeln(" ls [-l] [-R] [path]"); + ush_writeln(" cat [file] (reads pipeline input when file omitted)"); + ush_writeln(" grep [-n] [file]"); + ush_writeln(" pwd"); + ush_writeln(" cd [dir]"); + ush_writeln(" exec|run "); + ush_writeln(" clear"); + ush_writeln(" ansi / ansitest / color"); + ush_writeln(" fastfetch [--plain]"); + ush_writeln(" memstat / fsstat / taskstat / userstat / shstat / stats"); + ush_writeln(" tty [index]"); + ush_writeln(" dmesg [n]"); + ush_writeln(" kbdstat"); + ush_writeln(" mkdir (/temp only)"); + ush_writeln(" touch (/temp only)"); + ush_writeln(" write (/temp only, or from pipeline)"); + ush_writeln(" append (/temp only, or from pipeline)"); + ush_writeln(" cp (dst /temp only)"); + ush_writeln(" mv (/temp only)"); + ush_writeln(" rm (/temp only)"); + ush_writeln(" pid"); + ush_writeln(" spawn "); + ush_writeln(" wait "); + ush_writeln(" sleep "); + ush_writeln(" yield"); + ush_writeln(" shutdown / restart"); + ush_writeln(" exit [code]"); + ush_writeln(" rusttest / panic / elfloader (kernel shell only)"); + ush_writeln("pipeline/redirection: cmd1 | cmd2 | cmd3 > /temp/out.txt"); + ush_writeln("redirection append: cmd >> /temp/out.txt"); + ush_writeln("edit keys: Left/Right, Home/End, Up/Down history"); + return 1; +} -#include "cmd/ls_join_path.inc" +static int ush_ls_join_path(const char *dir_path, const char *name, char *out_path, u64 out_size) { + u64 p = 0ULL; + u64 i; -#include "cmd/ls_basename.inc" + if (dir_path == (const char *)0 || name == (const char *)0 || out_path == (char *)0 || out_size == 0ULL) { + return 0; + } -#include "cmd/ls_is_dot_entry.inc" + if (dir_path[0] == '/' && dir_path[1] == '\0') { + if (out_size < 2ULL) { + return 0; + } -#include "cmd/ls_print_one.inc" + out_path[p++] = '/'; + } else { + for (i = 0ULL; dir_path[i] != '\0'; i++) { + if (p + 1ULL >= out_size) { + return 0; + } -#include "cmd/ls_parse_args.inc" + out_path[p++] = dir_path[i]; + } -#include "cmd/ls_dir.inc" + if (p == 0ULL || out_path[p - 1ULL] != '/') { + if (p + 1ULL >= out_size) { + return 0; + } -#include "cmd/ls.inc" + out_path[p++] = '/'; + } + } -#include "cmd/cat.inc" + for (i = 0ULL; name[i] != '\0'; i++) { + if (p + 1ULL >= out_size) { + return 0; + } -#include "cmd/grep_write_u64_dec.inc" + out_path[p++] = name[i]; + } -#include "cmd/grep_line_has_pattern.inc" + out_path[p] = '\0'; + return 1; +} -#include "cmd/grep_emit_matches.inc" +static const char *ush_ls_basename(const char *path) { + const char *name = path; + u64 i = 0ULL; -#include "cmd/grep.inc" -#include "cmd/pwd.inc" + if (path == (const char *)0 || path[0] == '\0') { + return ""; + } -#include "cmd/cd.inc" + while (path[i] != '\0') { + if (path[i] == '/' && path[i + 1ULL] != '\0') { + name = &path[i + 1ULL]; + } -#include "cmd/exec.inc" + i++; + } -#include "cmd/pid.inc" + return name; +} -#include "cmd/spawn.inc" +static int ush_ls_is_dot_entry(const char *name) { + if (name == (const char *)0) { + return 0; + } -#include "cmd/wait.inc" + if (name[0] == '.' && name[1] == '\0') { + return 1; + } -#include "cmd/sleep.inc" + if (name[0] == '.' && name[1] == '.' && name[2] == '\0') { + return 1; + } -#include "cmd/yield.inc" + return 0; +} +static void ush_ls_print_one(const char *name, u64 type, u64 size, int long_mode) { + if (long_mode == 0) { + ush_writeln(name); + return; + } -#include "cmd/shutdown.inc" + if (type == 2ULL) { + ush_write("d "); + } else if (type == 1ULL) { + ush_write("f "); + } else { + ush_write("? "); + } -#include "cmd/restart.inc" + ush_write(name); -#include "cmd/exit.inc" + if (type == 1ULL) { + ush_write(" size="); + ush_write_hex_u64(size); + } else if (type == 2ULL) { + ush_write(" "); + } else { + ush_write(" "); + } -#include "cmd/clear.inc" + ush_write_char('\n'); +} -#include "cmd/ansi.inc" +static int ush_ls_parse_args(const char *arg, + int *out_long_mode, + int *out_recursive, + char *out_target, + u64 out_target_size) { + char token[USH_PATH_MAX]; + u64 i = 0ULL; + int path_set = 0; -#include "cmd/ansitest_u64_to_dec.inc" + if (out_long_mode == (int *)0 || + out_recursive == (int *)0 || + out_target == (char *)0 || + out_target_size == 0ULL) { + return 0; + } -#include "cmd/ansitest_emit_bg256.inc" + *out_long_mode = 0; + *out_recursive = 0; + ush_copy(out_target, out_target_size, "."); -#include "cmd/ansitest.inc" -#include "cmd/fastfetch_u64_to_dec.inc" + if (arg == (const char *)0 || arg[0] == '\0') { + return 1; + } -#include "cmd/fastfetch_write_u64_dec.inc" + while (arg[i] != '\0') { + u64 p = 0ULL; + u64 j; -#include "cmd/fastfetch_write_key.inc" + while (arg[i] != '\0' && ush_is_space(arg[i]) != 0) { + i++; + } -#include "cmd/fastfetch_print_text.inc" + if (arg[i] == '\0') { + break; + } -#include "cmd/fastfetch_print_u64.inc" + while (arg[i] != '\0' && ush_is_space(arg[i]) == 0) { + if (p + 1ULL < (u64)sizeof(token)) { + token[p++] = arg[i]; + } -#include "cmd/fastfetch_print_logo.inc" + i++; + } -#include "cmd/fastfetch_print_palette.inc" + token[p] = '\0'; -#include "cmd/fastfetch.inc" -#include "cmd/kbdstat.inc" + if (token[0] == '-' && token[1] != '\0') { + for (j = 1ULL; token[j] != '\0'; j++) { + if (token[j] == 'l') { + *out_long_mode = 1; + } else if (token[j] == 'R') { + *out_recursive = 1; + } else { + return 0; + } + } -#include "cmd/memstat.inc" + continue; + } -#include "cmd/fsstat.inc" + if (path_set != 0) { + return 0; + } -#include "cmd/taskstat.inc" + ush_copy(out_target, out_target_size, token); + path_set = 1; + } -#include "cmd/userstat.inc" + return 1; +} -#include "cmd/shstat.inc" +static int ush_ls_dir(const char *path, + int long_mode, + int recursive, + int print_header, + u64 depth) { + u64 count; + u64 i; -#include "cmd/tty.inc" + if (depth > 16ULL) { + ush_writeln("ls: recursion depth limit reached"); + return 0; + } -#include "cmd/dmesg.inc" + count = cleonos_sys_fs_child_count(path); -#include "cmd/mkdir.inc" + if (print_header != 0) { + ush_write(path); + ush_writeln(":"); + } -#include "cmd/touch.inc" + if (count == 0ULL) { + ush_writeln("(empty)"); + } -#include "cmd/write.inc" + for (i = 0ULL; i < count; i++) { + char name[CLEONOS_FS_NAME_MAX]; + char child_path[USH_PATH_MAX]; + u64 type; + u64 size = 0ULL; -#include "cmd/append.inc" + name[0] = '\0'; -#include "cmd/copy_file.inc" + if (cleonos_sys_fs_get_child_name(path, i, name) == 0ULL) { + continue; + } -#include "cmd/cp.inc" + if (ush_ls_join_path(path, name, child_path, (u64)sizeof(child_path)) == 0) { + continue; + } -#include "cmd/mv.inc" + type = cleonos_sys_fs_stat_type(child_path); -#include "cmd/rm.inc" + if (type == 1ULL) { + size = cleonos_sys_fs_stat_size(child_path); + } -#include "cmd/stats.inc" + ush_ls_print_one(name, type, size, long_mode); + } -#include "cmd/not_supported.inc" + if (recursive == 0) { + return 1; + } + + for (i = 0ULL; i < count; i++) { + char name[CLEONOS_FS_NAME_MAX]; + char child_path[USH_PATH_MAX]; + + name[0] = '\0'; + + if (cleonos_sys_fs_get_child_name(path, i, name) == 0ULL) { + continue; + } + + if (ush_ls_is_dot_entry(name) != 0) { + continue; + } + + if (ush_ls_join_path(path, name, child_path, (u64)sizeof(child_path)) == 0) { + continue; + } + + if (cleonos_sys_fs_stat_type(child_path) == 2ULL) { + ush_write_char('\n'); + (void)ush_ls_dir(child_path, long_mode, recursive, 1, depth + 1ULL); + } + } + + return 1; +} + +static int ush_cmd_ls(const ush_state *sh, const char *arg) { + char target[USH_PATH_MAX]; + char path[USH_PATH_MAX]; + u64 type; + int long_mode; + int recursive; + + if (ush_ls_parse_args(arg, &long_mode, &recursive, target, (u64)sizeof(target)) == 0) { + ush_writeln("ls: usage ls [-l] [-R] [path]"); + return 0; + } + + if (ush_resolve_path(sh, target, path, (u64)sizeof(path)) == 0) { + ush_writeln("ls: invalid path"); + return 0; + } + + type = cleonos_sys_fs_stat_type(path); + + if (type == 1ULL) { + u64 size = cleonos_sys_fs_stat_size(path); + ush_ls_print_one(ush_ls_basename(path), type, size, long_mode); + return 1; + } + + if (type != 2ULL) { + ush_writeln("ls: path not found"); + return 0; + } + + return ush_ls_dir(path, long_mode, recursive, recursive, 0ULL); +} + +static int ush_cmd_cat(const ush_state *sh, const char *arg) { + char path[USH_PATH_MAX]; + char buf[USH_CAT_MAX + 1ULL]; + u64 size; + u64 req; + u64 got; + + if (arg == (const char *)0 || arg[0] == '\0') { + if (ush_pipeline_stdin_text != (const char *)0 && ush_pipeline_stdin_len > 0ULL) { + ush_write(ush_pipeline_stdin_text); + return 1; + } + + ush_writeln("cat: file path required"); + return 0; + } + + if (ush_resolve_path(sh, arg, path, (u64)sizeof(path)) == 0) { + ush_writeln("cat: invalid path"); + return 0; + } + + if (cleonos_sys_fs_stat_type(path) != 1ULL) { + ush_writeln("cat: file not found"); + return 0; + } + + size = cleonos_sys_fs_stat_size(path); + + if (size == (u64)-1) { + ush_writeln("cat: failed to stat file"); + return 0; + } + + if (size == 0ULL) { + return 1; + } + + req = (size < USH_CAT_MAX) ? size : USH_CAT_MAX; + got = cleonos_sys_fs_read(path, buf, req); + + if (got == 0ULL) { + ush_writeln("cat: read failed"); + return 0; + } + + if (got > USH_CAT_MAX) { + got = USH_CAT_MAX; + } + + buf[got] = '\0'; + ush_writeln(buf); + + if (size > got) { + ush_writeln("[cat] output truncated"); + } + + return 1; +} + +static void ush_grep_write_u64_dec(u64 value) { + char tmp[32]; + u64 len = 0ULL; + + if (value == 0ULL) { + ush_write_char('0'); + return; + } + + while (value > 0ULL && len < (u64)sizeof(tmp)) { + tmp[len++] = (char)('0' + (value % 10ULL)); + value /= 10ULL; + } + + while (len > 0ULL) { + len--; + ush_write_char(tmp[len]); + } +} + +static int ush_grep_line_has_pattern(const char *line, u64 line_len, const char *pattern, u64 pattern_len) { + u64 i; + + if (line == (const char *)0 || pattern == (const char *)0) { + return 0; + } + + if (pattern_len == 0ULL) { + return 1; + } + + if (pattern_len > line_len) { + return 0; + } + + for (i = 0ULL; i + pattern_len <= line_len; i++) { + u64 j = 0ULL; + + while (j < pattern_len && line[i + j] == pattern[j]) { + j++; + } + + if (j == pattern_len) { + return 1; + } + } + + return 0; +} + +static u64 ush_grep_emit_matches(const char *input, u64 input_len, const char *pattern, int with_line_number) { + u64 matches = 0ULL; + u64 line_no = 1ULL; + u64 start = 0ULL; + u64 i; + u64 pattern_len; + + if (input == (const char *)0 || pattern == (const char *)0) { + return 0ULL; + } + + pattern_len = ush_strlen(pattern); + + for (i = 0ULL; i <= input_len; i++) { + if (i == input_len || input[i] == '\n') { + u64 line_len = i - start; + + if (ush_grep_line_has_pattern(&input[start], line_len, pattern, pattern_len) != 0) { + u64 j; + + matches++; + + if (with_line_number != 0) { + ush_grep_write_u64_dec(line_no); + ush_write(":"); + } + + for (j = 0ULL; j < line_len; j++) { + ush_write_char(input[start + j]); + } + + ush_write_char('\n'); + } + + start = i + 1ULL; + line_no++; + } + } + + return matches; +} + +static int ush_cmd_grep(const ush_state *sh, const char *arg) { + char first[USH_PATH_MAX]; + char second[USH_PATH_MAX]; + char third[USH_PATH_MAX]; + char path[USH_PATH_MAX]; + const char *rest = ""; + const char *rest2 = ""; + const char *pattern = (const char *)0; + const char *file_arg = (const char *)0; + const char *input = (const char *)0; + u64 input_len = 0ULL; + u64 size; + u64 got; + int with_line_number = 0; + static char file_buf[USH_COPY_MAX + 1U]; + + if (sh == (const ush_state *)0 || arg == (const char *)0 || arg[0] == '\0') { + ush_writeln("grep: usage grep [-n] [file]"); + return 0; + } + + if (ush_split_first_and_rest(arg, first, (u64)sizeof(first), &rest) == 0) { + ush_writeln("grep: usage grep [-n] [file]"); + return 0; + } + + if (ush_streq(first, "-n") != 0) { + with_line_number = 1; + + if (ush_split_first_and_rest(rest, second, (u64)sizeof(second), &rest2) == 0) { + ush_writeln("grep: usage grep [-n] [file]"); + return 0; + } + + pattern = second; + rest = rest2; + } else { + pattern = first; + } + + if (rest != (const char *)0 && rest[0] != '\0') { + if (ush_split_first_and_rest(rest, third, (u64)sizeof(third), &rest2) == 0) { + ush_writeln("grep: usage grep [-n] [file]"); + return 0; + } + + file_arg = third; + + if (rest2 != (const char *)0 && rest2[0] != '\0') { + ush_writeln("grep: usage grep [-n] [file]"); + return 0; + } + } + + if (pattern == (const char *)0 || pattern[0] == '\0') { + ush_writeln("grep: pattern required"); + return 0; + } + + if (file_arg != (const char *)0) { + if (ush_resolve_path(sh, file_arg, path, (u64)sizeof(path)) == 0) { + ush_writeln("grep: invalid path"); + return 0; + } + + if (cleonos_sys_fs_stat_type(path) != 1ULL) { + ush_writeln("grep: file not found"); + return 0; + } + + size = cleonos_sys_fs_stat_size(path); + + if (size == (u64)-1) { + ush_writeln("grep: failed to stat file"); + return 0; + } + + if (size > (u64)USH_COPY_MAX) { + ush_writeln("grep: file too large for user buffer"); + return 0; + } + + if (size == 0ULL) { + return 1; + } + + got = cleonos_sys_fs_read(path, file_buf, size); + + if (got == 0ULL || got != size) { + ush_writeln("grep: read failed"); + return 0; + } + + file_buf[got] = '\0'; + input = file_buf; + input_len = got; + } else { + if (ush_pipeline_stdin_text == (const char *)0) { + ush_writeln("grep: file path required (or pipeline input)"); + return 0; + } + + input = ush_pipeline_stdin_text; + input_len = ush_pipeline_stdin_len; + } + + (void)ush_grep_emit_matches(input, input_len, pattern, with_line_number); + return 1; +} + +static int ush_cmd_pwd(const ush_state *sh) { + ush_writeln(sh->cwd); + return 1; +} + +static int ush_cmd_cd(ush_state *sh, const char *arg) { + const char *target = arg; + char path[USH_PATH_MAX]; + + if (target == (const char *)0 || target[0] == '\0') { + target = "/"; + } + + if (ush_resolve_path(sh, target, path, (u64)sizeof(path)) == 0) { + ush_writeln("cd: invalid path"); + return 0; + } + + if (cleonos_sys_fs_stat_type(path) != 2ULL) { + ush_writeln("cd: directory not found"); + return 0; + } + + ush_copy(sh->cwd, (u64)sizeof(sh->cwd), path); + return 1; +} + +static int ush_cmd_exec(const ush_state *sh, const char *arg) { + char path[USH_PATH_MAX]; + u64 status; + + if (ush_resolve_exec_path(sh, arg, path, (u64)sizeof(path)) == 0) { + ush_writeln("exec: invalid target"); + return 0; + } + + if (ush_path_is_under_system(path) != 0) { + ush_writeln("exec: /system/*.elf is kernel-mode (KELF), not user-exec"); + return 0; + } + + status = cleonos_sys_exec_path(path); + + if (status == (u64)-1) { + ush_writeln("exec: request failed"); + return 0; + } + + if (status == 0ULL) { + ush_writeln("exec: request accepted"); + return 1; + } + + ush_writeln("exec: returned non-zero status"); + return 0; +} + +static int ush_cmd_pid(void) { + ush_print_kv_hex("PID", cleonos_sys_getpid()); + return 1; +} + +static int ush_cmd_spawn(const ush_state *sh, const char *arg) { + char path[USH_PATH_MAX]; + u64 pid; + + if (ush_resolve_exec_path(sh, arg, path, (u64)sizeof(path)) == 0) { + ush_writeln("spawn: invalid target"); + return 0; + } + + if (ush_path_is_under_system(path) != 0) { + ush_writeln("spawn: /system/*.elf is kernel-mode (KELF), not user-exec"); + return 0; + } + + pid = cleonos_sys_spawn_path(path); + + if (pid == (u64)-1) { + ush_writeln("spawn: request failed"); + return 0; + } + + ush_writeln("spawn: completed"); + ush_print_kv_hex(" PID", pid); + return 1; +} + +static int ush_cmd_wait(const char *arg) { + u64 pid; + u64 status = (u64)-1; + u64 wait_ret; + + if (arg == (const char *)0 || arg[0] == '\0') { + ush_writeln("wait: usage wait "); + return 0; + } + + if (ush_parse_u64_dec(arg, &pid) == 0) { + ush_writeln("wait: invalid pid"); + return 0; + } + + wait_ret = cleonos_sys_wait_pid(pid, &status); + + if (wait_ret == (u64)-1) { + ush_writeln("wait: pid not found"); + return 0; + } + + if (wait_ret == 0ULL) { + ush_writeln("wait: still running"); + return 1; + } + + ush_writeln("wait: exited"); + ush_print_kv_hex(" STATUS", status); + return 1; +} + +static int ush_cmd_sleep(const char *arg) { + u64 ticks; + u64 elapsed; + + if (arg == (const char *)0 || arg[0] == '\0') { + ush_writeln("sleep: usage sleep "); + return 0; + } + + if (ush_parse_u64_dec(arg, &ticks) == 0) { + ush_writeln("sleep: invalid ticks"); + return 0; + } + + elapsed = cleonos_sys_sleep_ticks(ticks); + ush_print_kv_hex("SLEPT_TICKS", elapsed); + return 1; +} + +static int ush_cmd_yield(void) { + ush_print_kv_hex("YIELD_TICK", cleonos_sys_yield()); + return 1; +} + +static int ush_cmd_shutdown(void) { + ush_writeln("shutdown: powering off..."); + (void)cleonos_sys_shutdown(); + return 1; +} + +static int ush_cmd_restart(void) { + ush_writeln("restart: rebooting..."); + (void)cleonos_sys_restart(); + return 1; +} + +static int ush_cmd_exit(ush_state *sh, const char *arg) { + u64 code = 0ULL; + + if (sh == (ush_state *)0) { + return 0; + } + + if (arg != (const char *)0 && arg[0] != '\0') { + if (ush_parse_u64_dec(arg, &code) == 0) { + ush_writeln("exit: usage exit [code]"); + return 0; + } + } + + sh->exit_requested = 1; + sh->exit_code = code; + (void)cleonos_sys_exit(code); + ush_writeln("exit: shell stopping"); + return 1; +} + +static int ush_cmd_clear(void) { + ush_write("\x1B[2J\x1B[H"); + return 1; +} + +static int ush_cmd_ansi(void) { + ush_writeln("\x1B[1;36mansi color demo\x1B[0m"); + ush_writeln(" \x1B[30mblack\x1B[0m \x1B[31mred\x1B[0m \x1B[32mgreen\x1B[0m \x1B[33myellow\x1B[0m"); + ush_writeln(" \x1B[34mblue\x1B[0m \x1B[35mmagenta\x1B[0m \x1B[36mcyan\x1B[0m \x1B[37mwhite\x1B[0m"); + ush_writeln(" \x1B[90mbright-black\x1B[0m \x1B[91mbright-red\x1B[0m \x1B[92mbright-green\x1B[0m \x1B[93mbright-yellow\x1B[0m"); + ush_writeln(" \x1B[94mbright-blue\x1B[0m \x1B[95mbright-magenta\x1B[0m \x1B[96mbright-cyan\x1B[0m \x1B[97mbright-white\x1B[0m"); + return 1; +} + +static u64 ush_ansitest_u64_to_dec(char *out, u64 out_size, u64 value) { + char rev[10]; + u64 digits = 0ULL; + u64 i; + + if (out == (char *)0 || out_size == 0ULL) { + return 0ULL; + } + + if (value == 0U) { + if (out_size < 2ULL) { + return 0ULL; + } + + out[0] = '0'; + out[1] = '\0'; + return 1ULL; + } + + while (value > 0U && digits < (u64)sizeof(rev)) { + rev[digits++] = (char)('0' + (value % 10U)); + value /= 10U; + } + + if (digits + 1ULL > out_size) { + out[0] = '\0'; + return 0ULL; + } + + for (i = 0ULL; i < digits; i++) { + out[i] = rev[digits - 1ULL - i]; + } + + out[digits] = '\0'; + return digits; +} + +static void ush_ansitest_emit_bg256(u64 index) { + char num[4]; + char seq[24]; + u64 digits; + u64 p = 0ULL; + u64 i; + + if (index > 255U) { + index = 255U; + } + + digits = ush_ansitest_u64_to_dec(num, (u64)sizeof(num), index); + if (digits == 0ULL) { + return; + } + + seq[p++] = '\x1B'; + seq[p++] = '['; + seq[p++] = '4'; + seq[p++] = '8'; + seq[p++] = ';'; + seq[p++] = '5'; + seq[p++] = ';'; + + for (i = 0ULL; i < digits && p + 1ULL < (u64)sizeof(seq); i++) { + seq[p++] = num[i]; + } + + if (p + 7ULL >= (u64)sizeof(seq)) { + return; + } + + seq[p++] = 'm'; + seq[p++] = ' '; + seq[p++] = ' '; + seq[p++] = '\x1B'; + seq[p++] = '['; + seq[p++] = '0'; + seq[p++] = 'm'; + seq[p] = '\0'; + + ush_write(seq); +} + +static int ush_cmd_ansitest(void) { + u64 i; + + ush_writeln("\x1B[1;96mANSI test suite\x1B[0m"); + ush_writeln("styles: \x1B[1mbold\x1B[0m \x1B[7minverse\x1B[0m \x1B[4munderline\x1B[0m"); + ush_writeln("16-color demo:"); + (void)ush_cmd_ansi(); + + ush_writeln("256-color palette (0..255):"); + for (i = 0ULL; i < 256ULL; i++) { + ush_ansitest_emit_bg256(i); + if ((i % 32ULL) == 31ULL) { + ush_write_char('\n'); + } + } + ush_write_char('\n'); + + ush_writeln("truecolor demo:"); + ush_writeln(" \x1B[38;2;255;64;64mRGB(255,64,64)\x1B[0m \x1B[38;2;64;255;64mRGB(64,255,64)\x1B[0m \x1B[38;2;64;128;255mRGB(64,128,255)\x1B[0m"); + + ush_writeln("cursor control demo:"); + ush_write(" 0123456789"); + ush_write("\x1B[5D"); + ush_write("\x1B[93m\x1B[0m"); + ush_write_char('\n'); + + ush_write(" save"); + ush_write("\x1B[s"); + ush_write("...."); + ush_write("\x1B[u"); + ush_write("\x1B[92m\x1B[0m"); + ush_write_char('\n'); + + ush_writeln("erase-line demo:"); + ush_write(" left|right-to-clear"); + ush_write("\x1B[14D\x1B[K"); + ush_write_char('\n'); + + ush_writeln("ansitest done"); + return 1; +} + +static u64 ush_fastfetch_u64_to_dec(char *out, u64 out_size, u64 value) { + char rev[32]; + u64 digits = 0ULL; + u64 i; + + if (out == (char *)0 || out_size == 0ULL) { + return 0ULL; + } + + if (value == 0ULL) { + if (out_size < 2ULL) { + return 0ULL; + } + out[0] = '0'; + out[1] = '\0'; + return 1ULL; + } + + while (value > 0ULL && digits < (u64)sizeof(rev)) { + rev[digits++] = (char)('0' + (value % 10ULL)); + value /= 10ULL; + } + + if (digits + 1ULL > out_size) { + out[0] = '\0'; + return 0ULL; + } + + for (i = 0ULL; i < digits; i++) { + out[i] = rev[digits - 1ULL - i]; + } + out[digits] = '\0'; + return digits; +} + +static void ush_fastfetch_write_u64_dec(u64 value) { + char text[32]; + + if (ush_fastfetch_u64_to_dec(text, (u64)sizeof(text), value) == 0ULL) { + ush_write("0"); + return; + } + + ush_write(text); +} + +static void ush_fastfetch_write_key(int plain, const char *key) { + ush_write(" "); + if (plain == 0) { + ush_write("\x1B[1;96m"); + } + ush_write(key); + if (plain == 0) { + ush_write("\x1B[0m"); + } + ush_write(": "); +} + +static void ush_fastfetch_print_text(int plain, const char *key, const char *value) { + ush_fastfetch_write_key(plain, key); + ush_writeln(value); +} + +static void ush_fastfetch_print_u64(int plain, const char *key, u64 value) { + ush_fastfetch_write_key(plain, key); + ush_fastfetch_write_u64_dec(value); + ush_write_char('\n'); +} + +static void ush_fastfetch_print_logo(int plain) { + if (plain == 0) { + ush_writeln("\x1B[1;34m $$$$$$\\ $$\\ $$$$$$\\ $$$$$$\\ \x1B[0m"); + ush_writeln("\x1B[1;36m$$ __$$\\ $$ | $$ __$$\\ $$ __$$\\ \x1B[0m"); + ush_writeln("\x1B[1;32m$$ / \\__|$$ | $$$$$$\\ $$$$$$\\ $$$$$$$\\ $$ / $$ |$$ / \\__|\x1B[0m"); + ush_writeln("\x1B[1;33m$$ | $$ | $$ __$$\\ $$ __$$\\ $$ __$$\\ $$ | $$ |\\$$$$$$\\ \x1B[0m"); + ush_writeln("\x1B[1;31m$$ | $$ | $$$$$$$$ |$$ / $$ |$$ | $$ |$$ | $$ | \\____$$\\ \x1B[0m"); + ush_writeln("\x1B[1;35m$$ | $$\\ $$ | $$ ____|$$ | $$ |$$ | $$ |$$ | $$ |$$\\ $$ |\x1B[0m"); + ush_writeln("\x1B[1;94m\\$$$$$$ |$$$$$$$$\\ \\$$$$$$$\\ \\$$$$$$ |$$ | $$ | $$$$$$ |\\$$$$$$ |\x1B[0m"); + ush_writeln("\x1B[1;96m \\______/ \\________| \\_______| \\______/ \\__| \\__| \\______/ \\______/ \x1B[0m"); + ush_writeln(" "); + ush_writeln(" "); + } else { + ush_writeln(" $$$$$$\\ $$\\ $$$$$$\\ $$$$$$\\ "); + ush_writeln("$$ __$$\\ $$ | $$ __$$\\ $$ __$$\\ "); + ush_writeln("$$ / \\__|$$ | $$$$$$\\ $$$$$$\\ $$$$$$$\\ $$ / $$ |$$ / \\__|"); + ush_writeln("$$ | $$ | $$ __$$\\ $$ __$$\\ $$ __$$\\ $$ | $$ |\\$$$$$$\\ "); + ush_writeln("$$ | $$ | $$$$$$$$ |$$ / $$ |$$ | $$ |$$ | $$ | \\____$$\\ "); + ush_writeln("$$ | $$\\ $$ | $$ ____|$$ | $$ |$$ | $$ |$$ | $$ |$$\\ $$ |"); + ush_writeln("\\$$$$$$ |$$$$$$$$\\ \\$$$$$$$\\ \\$$$$$$ |$$ | $$ | $$$$$$ |\\$$$$$$ |"); + ush_writeln(" \\______/ \\________| \\_______| \\______/ \\__| \\__| \\______/ \\______/ "); + ush_writeln(" "); + ush_writeln(" "); + } +} + +static void ush_fastfetch_print_palette(int plain) { + ush_fastfetch_write_key(plain, "Palette"); + + if (plain != 0) { + ush_writeln("ANSI16"); + return; + } + + ush_write("\x1B[40m \x1B[0m\x1B[41m \x1B[0m\x1B[42m \x1B[0m\x1B[43m \x1B[0m"); + ush_write("\x1B[44m \x1B[0m\x1B[45m \x1B[0m\x1B[46m \x1B[0m\x1B[47m \x1B[0m "); + ush_write("\x1B[100m \x1B[0m\x1B[101m \x1B[0m\x1B[102m \x1B[0m\x1B[103m \x1B[0m"); + ush_write("\x1B[104m \x1B[0m\x1B[105m \x1B[0m\x1B[106m \x1B[0m\x1B[107m \x1B[0m"); + ush_write_char('\n'); +} + +static int ush_cmd_fastfetch(const char *arg) { + int plain = 0; + u64 tty_active; + u64 tty_count; + u64 exec_req; + u64 exec_ok; + + if (arg != (const char *)0 && arg[0] != '\0') { + if (ush_streq(arg, "--plain") != 0) { + plain = 1; + } else if (ush_streq(arg, "--help") != 0 || ush_streq(arg, "-h") != 0) { + ush_writeln("usage: fastfetch [--plain]"); + return 1; + } else { + ush_writeln("fastfetch: usage fastfetch [--plain]"); + return 0; + } + } + + tty_active = cleonos_sys_tty_active(); + tty_count = cleonos_sys_tty_count(); + exec_req = cleonos_sys_exec_request_count(); + exec_ok = cleonos_sys_exec_success_count(); + + ush_fastfetch_print_logo(plain); + ush_write_char('\n'); + + ush_fastfetch_print_text(plain, "OS", "CLeonOS x86_64"); + ush_fastfetch_print_text(plain, "Shell", "User Shell (/shell/shell.elf)"); + ush_fastfetch_print_u64(plain, "PID", cleonos_sys_getpid()); + ush_fastfetch_print_u64(plain, "UptimeTicks", cleonos_sys_timer_ticks()); + ush_fastfetch_print_u64(plain, "Tasks", cleonos_sys_task_count()); + ush_fastfetch_print_u64(plain, "Services", cleonos_sys_service_count()); + ush_fastfetch_print_u64(plain, "SvcReady", cleonos_sys_service_ready_count()); + ush_fastfetch_print_u64(plain, "CtxSwitches", cleonos_sys_context_switches()); + ush_fastfetch_print_u64(plain, "KELFApps", cleonos_sys_kelf_count()); + ush_fastfetch_print_u64(plain, "KELFRuns", cleonos_sys_kelf_runs()); + ush_fastfetch_print_u64(plain, "FSNodes", cleonos_sys_fs_node_count()); + ush_fastfetch_print_u64(plain, "RootChildren", cleonos_sys_fs_child_count("/")); + + ush_fastfetch_write_key(plain, "TTY"); + ush_fastfetch_write_u64_dec(tty_active); + ush_write(" / "); + ush_fastfetch_write_u64_dec(tty_count); + ush_write_char('\n'); + + ush_fastfetch_write_key(plain, "ExecSuccess"); + ush_fastfetch_write_u64_dec(exec_ok); + ush_write(" / "); + ush_fastfetch_write_u64_dec(exec_req); + ush_write_char('\n'); + + ush_fastfetch_print_u64(plain, "KbdBuffered", cleonos_sys_kbd_buffered()); + ush_fastfetch_print_palette(plain); + return 1; +} + +static int ush_cmd_kbdstat(void) { + ush_writeln("kbdstat:"); + ush_print_kv_hex(" BUFFERED", cleonos_sys_kbd_buffered()); + ush_print_kv_hex(" PUSHED", cleonos_sys_kbd_pushed()); + ush_print_kv_hex(" POPPED", cleonos_sys_kbd_popped()); + ush_print_kv_hex(" DROPPED", cleonos_sys_kbd_dropped()); + ush_print_kv_hex(" HOTKEY_SWITCHES", cleonos_sys_kbd_hotkey_switches()); + return 1; +} + +static int ush_cmd_memstat(void) { + ush_writeln("memstat (user ABI limited):"); + ush_print_kv_hex(" SERVICE_COUNT", cleonos_sys_service_count()); + ush_print_kv_hex(" SERVICE_READY_COUNT", cleonos_sys_service_ready_count()); + ush_print_kv_hex(" KELF_COUNT", cleonos_sys_kelf_count()); + ush_print_kv_hex(" KELF_RUNS", cleonos_sys_kelf_runs()); + return 1; +} + +static int ush_cmd_fsstat(void) { + ush_writeln("fsstat:"); + ush_print_kv_hex(" NODE_COUNT", cleonos_sys_fs_node_count()); + ush_print_kv_hex(" ROOT_CHILDREN", cleonos_sys_fs_child_count("/")); + ush_print_kv_hex(" SYSTEM_CHILDREN", cleonos_sys_fs_child_count("/system")); + ush_print_kv_hex(" SHELL_CHILDREN", cleonos_sys_fs_child_count("/shell")); + ush_print_kv_hex(" TEMP_CHILDREN", cleonos_sys_fs_child_count("/temp")); + ush_print_kv_hex(" DRIVER_CHILDREN", cleonos_sys_fs_child_count("/driver")); + return 1; +} + +static int ush_cmd_taskstat(void) { + ush_writeln("taskstat:"); + ush_print_kv_hex(" TASK_COUNT", cleonos_sys_task_count()); + ush_print_kv_hex(" CURRENT_TASK", cleonos_syscall(CLEONOS_SYSCALL_CUR_TASK, 0ULL, 0ULL, 0ULL)); + ush_print_kv_hex(" TIMER_TICKS", cleonos_sys_timer_ticks()); + ush_print_kv_hex(" CONTEXT_SWITCHES", cleonos_sys_context_switches()); + return 1; +} + +static int ush_cmd_userstat(void) { + ush_writeln("userstat:"); + ush_print_kv_hex(" USER_SHELL_READY", cleonos_sys_user_shell_ready()); + ush_print_kv_hex(" USER_EXEC_REQUESTED", cleonos_sys_user_exec_requested()); + ush_print_kv_hex(" USER_LAUNCH_TRIES", cleonos_sys_user_launch_tries()); + ush_print_kv_hex(" USER_LAUNCH_OK", cleonos_sys_user_launch_ok()); + ush_print_kv_hex(" USER_LAUNCH_FAIL", cleonos_sys_user_launch_fail()); + ush_print_kv_hex(" EXEC_REQUESTS", cleonos_sys_exec_request_count()); + ush_print_kv_hex(" EXEC_SUCCESS", cleonos_sys_exec_success_count()); + ush_print_kv_hex(" TTY_COUNT", cleonos_sys_tty_count()); + ush_print_kv_hex(" TTY_ACTIVE", cleonos_sys_tty_active()); + return 1; +} + +static int ush_cmd_shstat(const ush_state *sh) { + ush_writeln("shstat:"); + ush_print_kv_hex(" CMD_TOTAL", sh->cmd_total); + ush_print_kv_hex(" CMD_OK", sh->cmd_ok); + ush_print_kv_hex(" CMD_FAIL", sh->cmd_fail); + ush_print_kv_hex(" CMD_UNKNOWN", sh->cmd_unknown); + ush_print_kv_hex(" EXIT_REQUESTED", (sh->exit_requested != 0) ? 1ULL : 0ULL); + ush_print_kv_hex(" EXIT_CODE", sh->exit_code); + return 1; +} + +static int ush_cmd_tty(const char *arg) { + u64 tty_count = cleonos_sys_tty_count(); + u64 active = cleonos_sys_tty_active(); + + if (arg == (const char *)0 || arg[0] == '\0') { + ush_print_kv_hex("TTY_COUNT", tty_count); + ush_print_kv_hex("TTY_ACTIVE", active); + return 1; + } + + { + u64 idx; + + if (ush_parse_u64_dec(arg, &idx) == 0) { + ush_writeln("tty: usage tty [index]"); + return 0; + } + + if (idx >= tty_count) { + ush_writeln("tty: index out of range"); + return 0; + } + + if (cleonos_sys_tty_switch(idx) == (u64)-1) { + ush_writeln("tty: switch failed"); + return 0; + } + + ush_writeln("tty: switched"); + ush_print_kv_hex("TTY_ACTIVE", cleonos_sys_tty_active()); + return 1; + } +} + +static int ush_cmd_dmesg(const char *arg) { + u64 total = cleonos_sys_log_journal_count(); + u64 limit = USH_DMESG_DEFAULT; + u64 start; + u64 i; + + if (arg != (const char *)0 && arg[0] != '\0') { + if (ush_parse_u64_dec(arg, &limit) == 0 || limit == 0ULL) { + ush_writeln("dmesg: usage dmesg [positive_count]"); + return 0; + } + } + + if (total == 0ULL) { + ush_writeln("(journal empty)"); + return 1; + } + + if (limit > total) { + limit = total; + } + + start = total - limit; + + for (i = start; i < total; i++) { + char line[USH_DMESG_LINE_MAX]; + + if (cleonos_sys_log_journal_read(i, line, (u64)sizeof(line)) != 0ULL) { + ush_writeln(line); + } + } + + return 1; +} + +static int ush_cmd_mkdir(const ush_state *sh, const char *arg) { + char path[USH_PATH_MAX]; + + if (arg == (const char *)0 || arg[0] == '\0') { + ush_writeln("mkdir: directory path required"); + return 0; + } + + if (ush_resolve_path(sh, arg, path, (u64)sizeof(path)) == 0) { + ush_writeln("mkdir: invalid path"); + return 0; + } + + if (ush_path_is_under_temp(path) == 0) { + ush_writeln("mkdir: target must be under /temp"); + return 0; + } + + if (cleonos_sys_fs_mkdir(path) == 0ULL) { + ush_writeln("mkdir: failed"); + return 0; + } + + return 1; +} + +static int ush_cmd_touch(const ush_state *sh, const char *arg) { + static const char empty_data[1] = {'\0'}; + char path[USH_PATH_MAX]; + + if (arg == (const char *)0 || arg[0] == '\0') { + ush_writeln("touch: file path required"); + return 0; + } + + if (ush_resolve_path(sh, arg, path, (u64)sizeof(path)) == 0) { + ush_writeln("touch: invalid path"); + return 0; + } + + if (ush_path_is_under_temp(path) == 0) { + ush_writeln("touch: target must be under /temp"); + return 0; + } + + if (cleonos_sys_fs_write(path, empty_data, 0ULL) == 0ULL) { + ush_writeln("touch: failed"); + return 0; + } + + return 1; +} + +static int ush_cmd_write(const ush_state *sh, const char *arg) { + char path_arg[USH_PATH_MAX]; + char abs_path[USH_PATH_MAX]; + const char *payload = (const char *)0; + u64 payload_len; + + if (arg == (const char *)0 || arg[0] == '\0') { + ush_writeln("write: usage write "); + return 0; + } + + if (ush_split_first_and_rest(arg, path_arg, (u64)sizeof(path_arg), &payload) == 0) { + ush_writeln("write: usage write "); + return 0; + } + + if (ush_resolve_path(sh, path_arg, abs_path, (u64)sizeof(abs_path)) == 0) { + ush_writeln("write: invalid path"); + return 0; + } + + if (ush_path_is_under_temp(abs_path) == 0) { + ush_writeln("write: target must be under /temp"); + return 0; + } + + if (payload == (const char *)0 || payload[0] == '\0') { + if (ush_pipeline_stdin_text == (const char *)0) { + ush_writeln("write: usage write "); + return 0; + } + payload = ush_pipeline_stdin_text; + payload_len = ush_pipeline_stdin_len; + } else { + payload_len = ush_strlen(payload); + } + + if (cleonos_sys_fs_write(abs_path, payload, payload_len) == 0ULL) { + ush_writeln("write: failed"); + return 0; + } + + return 1; +} + +static int ush_cmd_append(const ush_state *sh, const char *arg) { + char path_arg[USH_PATH_MAX]; + char abs_path[USH_PATH_MAX]; + const char *payload = (const char *)0; + u64 payload_len; + + if (arg == (const char *)0 || arg[0] == '\0') { + ush_writeln("append: usage append "); + return 0; + } + + if (ush_split_first_and_rest(arg, path_arg, (u64)sizeof(path_arg), &payload) == 0) { + ush_writeln("append: usage append "); + return 0; + } + + if (ush_resolve_path(sh, path_arg, abs_path, (u64)sizeof(abs_path)) == 0) { + ush_writeln("append: invalid path"); + return 0; + } + + if (ush_path_is_under_temp(abs_path) == 0) { + ush_writeln("append: target must be under /temp"); + return 0; + } + + if (payload == (const char *)0 || payload[0] == '\0') { + if (ush_pipeline_stdin_text == (const char *)0) { + ush_writeln("append: usage append "); + return 0; + } + payload = ush_pipeline_stdin_text; + payload_len = ush_pipeline_stdin_len; + } else { + payload_len = ush_strlen(payload); + } + + if (cleonos_sys_fs_append(abs_path, payload, payload_len) == 0ULL) { + ush_writeln("append: failed"); + return 0; + } + + return 1; +} + +static int ush_copy_file(const char *src_path, const char *dst_path) { + static char copy_buf[USH_COPY_MAX]; + u64 src_type; + u64 src_size; + u64 got; + + src_type = cleonos_sys_fs_stat_type(src_path); + + if (src_type != 1ULL) { + ush_writeln("cp: source file not found"); + return 0; + } + + src_size = cleonos_sys_fs_stat_size(src_path); + + if (src_size == (u64)-1) { + ush_writeln("cp: failed to stat source"); + return 0; + } + + if (src_size > (u64)USH_COPY_MAX) { + ush_writeln("cp: source too large for user shell buffer"); + return 0; + } + + if (src_size == 0ULL) { + got = 0ULL; + } else { + got = cleonos_sys_fs_read(src_path, copy_buf, src_size); + + if (got == 0ULL || got != src_size) { + ush_writeln("cp: failed to read source"); + return 0; + } + } + + if (cleonos_sys_fs_write(dst_path, copy_buf, got) == 0ULL) { + ush_writeln("cp: failed to write destination"); + return 0; + } + + return 1; +} + +static int ush_cmd_cp(const ush_state *sh, const char *arg) { + char src_arg[USH_PATH_MAX]; + char dst_arg[USH_PATH_MAX]; + char src_path[USH_PATH_MAX]; + char dst_path[USH_PATH_MAX]; + + if (arg == (const char *)0 || arg[0] == '\0') { + ush_writeln("cp: usage cp "); + return 0; + } + + if (ush_split_two_args(arg, src_arg, (u64)sizeof(src_arg), dst_arg, (u64)sizeof(dst_arg)) == 0) { + ush_writeln("cp: usage cp "); + return 0; + } + + if (ush_resolve_path(sh, src_arg, src_path, (u64)sizeof(src_path)) == 0 || + ush_resolve_path(sh, dst_arg, dst_path, (u64)sizeof(dst_path)) == 0) { + ush_writeln("cp: invalid path"); + return 0; + } + + if (ush_path_is_under_temp(dst_path) == 0) { + ush_writeln("cp: destination must be under /temp"); + return 0; + } + + return ush_copy_file(src_path, dst_path); +} + +static int ush_cmd_mv(const ush_state *sh, const char *arg) { + char src_arg[USH_PATH_MAX]; + char dst_arg[USH_PATH_MAX]; + char src_path[USH_PATH_MAX]; + char dst_path[USH_PATH_MAX]; + + if (arg == (const char *)0 || arg[0] == '\0') { + ush_writeln("mv: usage mv "); + return 0; + } + + if (ush_split_two_args(arg, src_arg, (u64)sizeof(src_arg), dst_arg, (u64)sizeof(dst_arg)) == 0) { + ush_writeln("mv: usage mv "); + return 0; + } + + if (ush_resolve_path(sh, src_arg, src_path, (u64)sizeof(src_path)) == 0 || + ush_resolve_path(sh, dst_arg, dst_path, (u64)sizeof(dst_path)) == 0) { + ush_writeln("mv: invalid path"); + return 0; + } + + if (ush_path_is_under_temp(src_path) == 0 || ush_path_is_under_temp(dst_path) == 0) { + ush_writeln("mv: source and destination must be under /temp"); + return 0; + } + + if (ush_copy_file(src_path, dst_path) == 0) { + return 0; + } + + if (cleonos_sys_fs_remove(src_path) == 0ULL) { + ush_writeln("mv: source remove failed"); + return 0; + } + + return 1; +} + +static int ush_cmd_rm(const ush_state *sh, const char *arg) { + char path[USH_PATH_MAX]; + + if (arg == (const char *)0 || arg[0] == '\0') { + ush_writeln("rm: path required"); + return 0; + } + + if (ush_resolve_path(sh, arg, path, (u64)sizeof(path)) == 0) { + ush_writeln("rm: invalid path"); + return 0; + } + + if (ush_path_is_under_temp(path) == 0) { + ush_writeln("rm: target must be under /temp"); + return 0; + } + + if (cleonos_sys_fs_remove(path) == 0ULL) { + ush_writeln("rm: failed (directory must be empty)"); + return 0; + } + + return 1; +} + +static int ush_cmd_stats(const ush_state *sh) { + (void)ush_cmd_memstat(); + (void)ush_cmd_fsstat(); + (void)ush_cmd_taskstat(); + (void)ush_cmd_userstat(); + (void)ush_cmd_kbdstat(); + (void)ush_cmd_shstat(sh); + return 1; +} + +static int ush_cmd_not_supported(const char *name, const char *why) { + ush_write(name); + ush_write(": "); + ush_writeln(why); + return 0; +} static int ush_execute_single_command(ush_state *sh, const char *cmd, @@ -668,3 +2063,4 @@ void ush_execute_line(ush_state *sh, const char *line) { } + diff --git a/cleonos/c/apps/shell/shell_external.c b/cleonos/c/apps/shell/shell_external.c index b63c084..4b8f68d 100644 --- a/cleonos/c/apps/shell/shell_external.c +++ b/cleonos/c/apps/shell/shell_external.c @@ -1,7 +1,5 @@ #include "shell_internal.h" -static int ush_dispatch_external_enabled = 1; - static void ush_zero(void *ptr, u64 size) { u64 i; char *bytes = (char *)ptr; @@ -47,44 +45,6 @@ static const char *ush_alias_command(const char *cmd) { return cmd; } -static int ush_build_command_line(const char *cmd, const char *arg, char *out_line, u64 out_size) { - u64 p = 0ULL; - u64 i; - - if (cmd == (const char *)0 || out_line == (char *)0 || out_size == 0ULL) { - return 0; - } - - out_line[0] = '\0'; - - for (i = 0ULL; cmd[i] != '\0'; i++) { - if (p + 1ULL >= out_size) { - return 0; - } - - out_line[p++] = cmd[i]; - } - - if (arg != (const char *)0 && arg[0] != '\0') { - if (p + 1ULL >= out_size) { - return 0; - } - - out_line[p++] = ' '; - - for (i = 0ULL; arg[i] != '\0'; i++) { - if (p + 1ULL >= out_size) { - return 0; - } - - out_line[p++] = arg[i]; - } - } - - out_line[p] = '\0'; - return 1; -} - static int ush_cmd_ret_apply(ush_state *sh, const ush_cmd_ret *ret) { if (sh == (ush_state *)0 || ret == (const ush_cmd_ret *)0) { return 0; @@ -102,10 +62,6 @@ static int ush_cmd_ret_apply(ush_state *sh, const ush_cmd_ret *ret) { return 1; } -void ush_set_external_dispatch(int enabled) { - ush_dispatch_external_enabled = (enabled != 0) ? 1 : 0; -} - int ush_command_ctx_write(const char *cmd, const char *arg, const char *cwd) { ush_cmd_ctx ctx; @@ -176,10 +132,6 @@ int ush_try_exec_external(ush_state *sh, const char *cmd, const char *arg, int * return 0; } - if (ush_dispatch_external_enabled == 0) { - return 0; - } - canonical = ush_alias_command(cmd); if (canonical == (const char *)0) { @@ -232,66 +184,3 @@ int ush_try_exec_external(ush_state *sh, const char *cmd, const char *arg, int * return 1; } - -int ush_command_program_main(const char *command_name) { - ush_cmd_ctx ctx; - ush_state sh; - ush_cmd_ret ret; - char line[USH_LINE_MAX]; - u64 ok_before; - int success; - int has_context = 0; - int use_ctx_cwd = 0; - - if (command_name == (const char *)0 || command_name[0] == '\0') { - return 1; - } - - ush_zero(&ctx, (u64)sizeof(ctx)); - - if (ush_command_ctx_read(&ctx) != 0) { - if (ush_streq(ctx.cmd, command_name) != 0) { - has_context = 1; - use_ctx_cwd = 1; - } else if (ctx.cwd[0] == '/') { - use_ctx_cwd = 1; - ctx.arg[0] = '\0'; - } - } - - ush_init_state(&sh); - ush_set_external_dispatch(0); - - if (use_ctx_cwd != 0 && ctx.cwd[0] == '/') { - ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); - } - - if (ush_build_command_line(command_name, ctx.arg, line, (u64)sizeof(line)) == 0) { - ush_set_external_dispatch(1); - ush_writeln("command line too long"); - return 1; - } - - ok_before = sh.cmd_ok; - ush_execute_line(&sh, line); - success = (sh.cmd_ok > ok_before) ? 1 : 0; - - if (has_context != 0) { - ush_zero(&ret, (u64)sizeof(ret)); - - if (ush_streq(sh.cwd, ctx.cwd) == 0) { - ret.flags |= USH_CMD_RET_FLAG_CWD; - ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); - } - - if (sh.exit_requested != 0) { - ret.flags |= USH_CMD_RET_FLAG_EXIT; - ret.exit_code = sh.exit_code; - } - - (void)ush_command_ret_write(&ret); - } - - ush_set_external_dispatch(1); - return (success != 0) ? 0 : 1; -} diff --git a/cleonos/c/apps/shell/shell_internal.h b/cleonos/c/apps/shell/shell_internal.h index 1020a34..b6192ca 100644 --- a/cleonos/c/apps/shell/shell_internal.h +++ b/cleonos/c/apps/shell/shell_internal.h @@ -99,14 +99,12 @@ int ush_path_is_under_system(const char *path); void ush_read_line(ush_state *sh, char *out_line, u64 out_size); int ush_run_script_file(ush_state *sh, const char *path); void ush_execute_line(ush_state *sh, const char *line); -void ush_set_external_dispatch(int enabled); int ush_command_ctx_write(const char *cmd, const char *arg, const char *cwd); int ush_command_ctx_read(ush_cmd_ctx *out_ctx); void ush_command_ret_reset(void); int ush_command_ret_write(const ush_cmd_ret *ret); int ush_command_ret_read(ush_cmd_ret *out_ret); -int ush_command_program_main(const char *command_name); int ush_try_exec_external(ush_state *sh, const char *cmd, const char *arg, int *out_success); #endif diff --git a/cleonos/c/apps/shstat_main.c b/cleonos/c/apps/shstat_main.c index d6e52cb..8bc53bf 100644 --- a/cleonos/c/apps/shstat_main.c +++ b/cleonos/c/apps/shstat_main.c @@ -1,6 +1,55 @@ -#include "shell/shell_internal.h" - -int cleonos_app_main(void) { - return ush_command_program_main("shstat"); +#include "cmd_runtime.h" +static int ush_cmd_shstat(const ush_state *sh) { + ush_writeln("shstat:"); + ush_print_kv_hex(" CMD_TOTAL", sh->cmd_total); + ush_print_kv_hex(" CMD_OK", sh->cmd_ok); + ush_print_kv_hex(" CMD_FAIL", sh->cmd_fail); + ush_print_kv_hex(" CMD_UNKNOWN", sh->cmd_unknown); + ush_print_kv_hex(" EXIT_REQUESTED", (sh->exit_requested != 0) ? 1ULL : 0ULL); + ush_print_kv_hex(" EXIT_CODE", sh->exit_code); + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "shstat") != 0) { + has_context = 1; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_shstat(&sh); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/shutdown_main.c b/cleonos/c/apps/shutdown_main.c index 10e473a..92d3592 100644 --- a/cleonos/c/apps/shutdown_main.c +++ b/cleonos/c/apps/shutdown_main.c @@ -1,6 +1,50 @@ -#include "shell/shell_internal.h" - -int cleonos_app_main(void) { - return ush_command_program_main("shutdown"); +#include "cmd_runtime.h" +static int ush_cmd_shutdown(void) { + ush_writeln("shutdown: powering off..."); + (void)cleonos_sys_shutdown(); + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "shutdown") != 0) { + has_context = 1; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_shutdown(); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/sleep_main.c b/cleonos/c/apps/sleep_main.c index fec5697..309105c 100644 --- a/cleonos/c/apps/sleep_main.c +++ b/cleonos/c/apps/sleep_main.c @@ -1,6 +1,65 @@ -#include "shell/shell_internal.h" +#include "cmd_runtime.h" +static int ush_cmd_sleep(const char *arg) { + u64 ticks; + u64 elapsed; -int cleonos_app_main(void) { - return ush_command_program_main("sleep"); + if (arg == (const char *)0 || arg[0] == '\0') { + ush_writeln("sleep: usage sleep "); + return 0; + } + + if (ush_parse_u64_dec(arg, &ticks) == 0) { + ush_writeln("sleep: invalid ticks"); + return 0; + } + + elapsed = cleonos_sys_sleep_ticks(ticks); + ush_print_kv_hex("SLEPT_TICKS", elapsed); + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + const char *arg = ""; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "sleep") != 0) { + has_context = 1; + arg = ctx.arg; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_sleep(arg); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/spawn_main.c b/cleonos/c/apps/spawn_main.c index 063de7d..5e0a9de 100644 --- a/cleonos/c/apps/spawn_main.c +++ b/cleonos/c/apps/spawn_main.c @@ -1,6 +1,72 @@ -#include "shell/shell_internal.h" +#include "cmd_runtime.h" +static int ush_cmd_spawn(const ush_state *sh, const char *arg) { + char path[USH_PATH_MAX]; + u64 pid; -int cleonos_app_main(void) { - return ush_command_program_main("spawn"); + if (ush_resolve_exec_path(sh, arg, path, (u64)sizeof(path)) == 0) { + ush_writeln("spawn: invalid target"); + return 0; + } + + if (ush_path_is_under_system(path) != 0) { + ush_writeln("spawn: /system/*.elf is kernel-mode (KELF), not user-exec"); + return 0; + } + + pid = cleonos_sys_spawn_path(path); + + if (pid == (u64)-1) { + ush_writeln("spawn: request failed"); + return 0; + } + + ush_writeln("spawn: completed"); + ush_print_kv_hex(" PID", pid); + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + const char *arg = ""; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "spawn") != 0) { + has_context = 1; + arg = ctx.arg; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_spawn(&sh, arg); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/stats_main.c b/cleonos/c/apps/stats_main.c index b2725bf..4049452 100644 --- a/cleonos/c/apps/stats_main.c +++ b/cleonos/c/apps/stats_main.c @@ -1,6 +1,118 @@ -#include "shell/shell_internal.h" - -int cleonos_app_main(void) { - return ush_command_program_main("stats"); +#include "cmd_runtime.h" +static int ush_cmd_memstat(void) { + ush_writeln("memstat (user ABI limited):"); + ush_print_kv_hex(" SERVICE_COUNT", cleonos_sys_service_count()); + ush_print_kv_hex(" SERVICE_READY_COUNT", cleonos_sys_service_ready_count()); + ush_print_kv_hex(" KELF_COUNT", cleonos_sys_kelf_count()); + ush_print_kv_hex(" KELF_RUNS", cleonos_sys_kelf_runs()); + return 1; +} + +static int ush_cmd_fsstat(void) { + ush_writeln("fsstat:"); + ush_print_kv_hex(" NODE_COUNT", cleonos_sys_fs_node_count()); + ush_print_kv_hex(" ROOT_CHILDREN", cleonos_sys_fs_child_count("/")); + ush_print_kv_hex(" SYSTEM_CHILDREN", cleonos_sys_fs_child_count("/system")); + ush_print_kv_hex(" SHELL_CHILDREN", cleonos_sys_fs_child_count("/shell")); + ush_print_kv_hex(" TEMP_CHILDREN", cleonos_sys_fs_child_count("/temp")); + ush_print_kv_hex(" DRIVER_CHILDREN", cleonos_sys_fs_child_count("/driver")); + return 1; +} + +static int ush_cmd_taskstat(void) { + ush_writeln("taskstat:"); + ush_print_kv_hex(" TASK_COUNT", cleonos_sys_task_count()); + ush_print_kv_hex(" CURRENT_TASK", cleonos_syscall(CLEONOS_SYSCALL_CUR_TASK, 0ULL, 0ULL, 0ULL)); + ush_print_kv_hex(" TIMER_TICKS", cleonos_sys_timer_ticks()); + ush_print_kv_hex(" CONTEXT_SWITCHES", cleonos_sys_context_switches()); + return 1; +} + +static int ush_cmd_userstat(void) { + ush_writeln("userstat:"); + ush_print_kv_hex(" USER_SHELL_READY", cleonos_sys_user_shell_ready()); + ush_print_kv_hex(" USER_EXEC_REQUESTED", cleonos_sys_user_exec_requested()); + ush_print_kv_hex(" USER_LAUNCH_TRIES", cleonos_sys_user_launch_tries()); + ush_print_kv_hex(" USER_LAUNCH_OK", cleonos_sys_user_launch_ok()); + ush_print_kv_hex(" USER_LAUNCH_FAIL", cleonos_sys_user_launch_fail()); + ush_print_kv_hex(" EXEC_REQUESTS", cleonos_sys_exec_request_count()); + ush_print_kv_hex(" EXEC_SUCCESS", cleonos_sys_exec_success_count()); + ush_print_kv_hex(" TTY_COUNT", cleonos_sys_tty_count()); + ush_print_kv_hex(" TTY_ACTIVE", cleonos_sys_tty_active()); + return 1; +} + +static int ush_cmd_kbdstat(void) { + ush_writeln("kbdstat:"); + ush_print_kv_hex(" BUFFERED", cleonos_sys_kbd_buffered()); + ush_print_kv_hex(" PUSHED", cleonos_sys_kbd_pushed()); + ush_print_kv_hex(" POPPED", cleonos_sys_kbd_popped()); + ush_print_kv_hex(" DROPPED", cleonos_sys_kbd_dropped()); + ush_print_kv_hex(" HOTKEY_SWITCHES", cleonos_sys_kbd_hotkey_switches()); + return 1; +} + +static int ush_cmd_shstat(const ush_state *sh) { + ush_writeln("shstat:"); + ush_print_kv_hex(" CMD_TOTAL", sh->cmd_total); + ush_print_kv_hex(" CMD_OK", sh->cmd_ok); + ush_print_kv_hex(" CMD_FAIL", sh->cmd_fail); + ush_print_kv_hex(" CMD_UNKNOWN", sh->cmd_unknown); + ush_print_kv_hex(" EXIT_REQUESTED", (sh->exit_requested != 0) ? 1ULL : 0ULL); + ush_print_kv_hex(" EXIT_CODE", sh->exit_code); + return 1; +} + +static int ush_cmd_stats(const ush_state *sh) { + (void)ush_cmd_memstat(); + (void)ush_cmd_fsstat(); + (void)ush_cmd_taskstat(); + (void)ush_cmd_userstat(); + (void)ush_cmd_kbdstat(); + (void)ush_cmd_shstat(sh); + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "stats") != 0) { + has_context = 1; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_stats(&sh); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/taskstat_main.c b/cleonos/c/apps/taskstat_main.c index 44a0bb9..93bcd61 100644 --- a/cleonos/c/apps/taskstat_main.c +++ b/cleonos/c/apps/taskstat_main.c @@ -1,6 +1,53 @@ -#include "shell/shell_internal.h" - -int cleonos_app_main(void) { - return ush_command_program_main("taskstat"); +#include "cmd_runtime.h" +static int ush_cmd_taskstat(void) { + ush_writeln("taskstat:"); + ush_print_kv_hex(" TASK_COUNT", cleonos_sys_task_count()); + ush_print_kv_hex(" CURRENT_TASK", cleonos_syscall(CLEONOS_SYSCALL_CUR_TASK, 0ULL, 0ULL, 0ULL)); + ush_print_kv_hex(" TIMER_TICKS", cleonos_sys_timer_ticks()); + ush_print_kv_hex(" CONTEXT_SWITCHES", cleonos_sys_context_switches()); + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "taskstat") != 0) { + has_context = 1; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_taskstat(); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/touch_main.c b/cleonos/c/apps/touch_main.c index d6f09d7..75c9a53 100644 --- a/cleonos/c/apps/touch_main.c +++ b/cleonos/c/apps/touch_main.c @@ -1,6 +1,73 @@ -#include "shell/shell_internal.h" +#include "cmd_runtime.h" +static int ush_cmd_touch(const ush_state *sh, const char *arg) { + static const char empty_data[1] = {'\0'}; + char path[USH_PATH_MAX]; -int cleonos_app_main(void) { - return ush_command_program_main("touch"); + if (arg == (const char *)0 || arg[0] == '\0') { + ush_writeln("touch: file path required"); + return 0; + } + + if (ush_resolve_path(sh, arg, path, (u64)sizeof(path)) == 0) { + ush_writeln("touch: invalid path"); + return 0; + } + + if (ush_path_is_under_temp(path) == 0) { + ush_writeln("touch: target must be under /temp"); + return 0; + } + + if (cleonos_sys_fs_write(path, empty_data, 0ULL) == 0ULL) { + ush_writeln("touch: failed"); + return 0; + } + + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + const char *arg = ""; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "touch") != 0) { + has_context = 1; + arg = ctx.arg; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_touch(&sh, arg); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/tty_main.c b/cleonos/c/apps/tty_main.c index bafad3f..fd13d38 100644 --- a/cleonos/c/apps/tty_main.c +++ b/cleonos/c/apps/tty_main.c @@ -1,6 +1,80 @@ -#include "shell/shell_internal.h" +#include "cmd_runtime.h" +static int ush_cmd_tty(const char *arg) { + u64 tty_count = cleonos_sys_tty_count(); + u64 active = cleonos_sys_tty_active(); -int cleonos_app_main(void) { - return ush_command_program_main("tty"); + if (arg == (const char *)0 || arg[0] == '\0') { + ush_print_kv_hex("TTY_COUNT", tty_count); + ush_print_kv_hex("TTY_ACTIVE", active); + return 1; + } + + { + u64 idx; + + if (ush_parse_u64_dec(arg, &idx) == 0) { + ush_writeln("tty: usage tty [index]"); + return 0; + } + + if (idx >= tty_count) { + ush_writeln("tty: index out of range"); + return 0; + } + + if (cleonos_sys_tty_switch(idx) == (u64)-1) { + ush_writeln("tty: switch failed"); + return 0; + } + + ush_writeln("tty: switched"); + ush_print_kv_hex("TTY_ACTIVE", cleonos_sys_tty_active()); + return 1; + } +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + const char *arg = ""; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "tty") != 0) { + has_context = 1; + arg = ctx.arg; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_tty(arg); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/userstat_main.c b/cleonos/c/apps/userstat_main.c index eaa3564..a922af7 100644 --- a/cleonos/c/apps/userstat_main.c +++ b/cleonos/c/apps/userstat_main.c @@ -1,6 +1,58 @@ -#include "shell/shell_internal.h" - -int cleonos_app_main(void) { - return ush_command_program_main("userstat"); +#include "cmd_runtime.h" +static int ush_cmd_userstat(void) { + ush_writeln("userstat:"); + ush_print_kv_hex(" USER_SHELL_READY", cleonos_sys_user_shell_ready()); + ush_print_kv_hex(" USER_EXEC_REQUESTED", cleonos_sys_user_exec_requested()); + ush_print_kv_hex(" USER_LAUNCH_TRIES", cleonos_sys_user_launch_tries()); + ush_print_kv_hex(" USER_LAUNCH_OK", cleonos_sys_user_launch_ok()); + ush_print_kv_hex(" USER_LAUNCH_FAIL", cleonos_sys_user_launch_fail()); + ush_print_kv_hex(" EXEC_REQUESTS", cleonos_sys_exec_request_count()); + ush_print_kv_hex(" EXEC_SUCCESS", cleonos_sys_exec_success_count()); + ush_print_kv_hex(" TTY_COUNT", cleonos_sys_tty_count()); + ush_print_kv_hex(" TTY_ACTIVE", cleonos_sys_tty_active()); + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "userstat") != 0) { + has_context = 1; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_userstat(); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/wait_main.c b/cleonos/c/apps/wait_main.c index de7e44f..43258ad 100644 --- a/cleonos/c/apps/wait_main.c +++ b/cleonos/c/apps/wait_main.c @@ -1,6 +1,78 @@ -#include "shell/shell_internal.h" +#include "cmd_runtime.h" +static int ush_cmd_wait(const char *arg) { + u64 pid; + u64 status = (u64)-1; + u64 wait_ret; -int cleonos_app_main(void) { - return ush_command_program_main("wait"); + if (arg == (const char *)0 || arg[0] == '\0') { + ush_writeln("wait: usage wait "); + return 0; + } + + if (ush_parse_u64_dec(arg, &pid) == 0) { + ush_writeln("wait: invalid pid"); + return 0; + } + + wait_ret = cleonos_sys_wait_pid(pid, &status); + + if (wait_ret == (u64)-1) { + ush_writeln("wait: pid not found"); + return 0; + } + + if (wait_ret == 0ULL) { + ush_writeln("wait: still running"); + return 1; + } + + ush_writeln("wait: exited"); + ush_print_kv_hex(" STATUS", status); + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + const char *arg = ""; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "wait") != 0) { + has_context = 1; + arg = ctx.arg; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_wait(arg); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/write_main.c b/cleonos/c/apps/write_main.c index 3f8ba77..4e07b95 100644 --- a/cleonos/c/apps/write_main.c +++ b/cleonos/c/apps/write_main.c @@ -1,6 +1,91 @@ -#include "shell/shell_internal.h" +#include "cmd_runtime.h" +static int ush_cmd_write(const ush_state *sh, const char *arg) { + char path_arg[USH_PATH_MAX]; + char abs_path[USH_PATH_MAX]; + const char *payload = (const char *)0; + u64 payload_len; -int cleonos_app_main(void) { - return ush_command_program_main("write"); + if (arg == (const char *)0 || arg[0] == '\0') { + ush_writeln("write: usage write "); + return 0; + } + + if (ush_split_first_and_rest(arg, path_arg, (u64)sizeof(path_arg), &payload) == 0) { + ush_writeln("write: usage write "); + return 0; + } + + if (ush_resolve_path(sh, path_arg, abs_path, (u64)sizeof(abs_path)) == 0) { + ush_writeln("write: invalid path"); + return 0; + } + + if (ush_path_is_under_temp(abs_path) == 0) { + ush_writeln("write: target must be under /temp"); + return 0; + } + + if (payload == (const char *)0 || payload[0] == '\0') { + if (ush_pipeline_stdin_text == (const char *)0) { + ush_writeln("write: usage write "); + return 0; + } + payload = ush_pipeline_stdin_text; + payload_len = ush_pipeline_stdin_len; + } else { + payload_len = ush_strlen(payload); + } + + if (cleonos_sys_fs_write(abs_path, payload, payload_len) == 0ULL) { + ush_writeln("write: failed"); + return 0; + } + + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + const char *arg = ""; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "write") != 0) { + has_context = 1; + arg = ctx.arg; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_write(&sh, arg); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; } diff --git a/cleonos/c/apps/yield_main.c b/cleonos/c/apps/yield_main.c index 402ba37..69b7e89 100644 --- a/cleonos/c/apps/yield_main.c +++ b/cleonos/c/apps/yield_main.c @@ -1,6 +1,49 @@ -#include "shell/shell_internal.h" - -int cleonos_app_main(void) { - return ush_command_program_main("yield"); +#include "cmd_runtime.h" +static int ush_cmd_yield(void) { + ush_print_kv_hex("YIELD_TICK", cleonos_sys_yield()); + return 1; +} + + +int cleonos_app_main(void) { + ush_cmd_ctx ctx; + ush_cmd_ret ret; + ush_state sh; + char initial_cwd[USH_PATH_MAX]; + int has_context = 0; + int success = 0; + + ush_zero(&ctx, (u64)sizeof(ctx)); + ush_zero(&ret, (u64)sizeof(ret)); + ush_init_state(&sh); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + + if (ush_command_ctx_read(&ctx) != 0) { + if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "yield") != 0) { + has_context = 1; + if (ctx.cwd[0] == '/') { + ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd); + ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd); + } + } + } + + success = ush_cmd_yield(); + + if (has_context != 0) { + if (ush_streq(sh.cwd, initial_cwd) == 0) { + ret.flags |= USH_CMD_RET_FLAG_CWD; + ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd); + } + + if (sh.exit_requested != 0) { + ret.flags |= USH_CMD_RET_FLAG_EXIT; + ret.exit_code = sh.exit_code; + } + + (void)ush_command_ret_write(&ret); + } + + return (success != 0) ? 0 : 1; }