From caf948f4f62e9bf7933a782005738704b7ecb3da Mon Sep 17 00:00:00 2001 From: Leonmmcoset Date: Sat, 18 Apr 2026 12:21:01 +0800 Subject: [PATCH] =?UTF-8?q?fd=E5=AD=90=E7=B3=BB=E7=BB=9F2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cleonos/c/apps/shell/shell_cmd.c | 183 +++++++++++++++++++++----- cleonos/c/apps/shell/shell_internal.h | 2 + cleonos/c/apps/shell/shell_util.c | 46 ++++++- 3 files changed, 196 insertions(+), 35 deletions(-) diff --git a/cleonos/c/apps/shell/shell_cmd.c b/cleonos/c/apps/shell/shell_cmd.c index a80517b..ed37135 100644 --- a/cleonos/c/apps/shell/shell_cmd.c +++ b/cleonos/c/apps/shell/shell_cmd.c @@ -5,6 +5,8 @@ #define USH_COPY_MAX 65536U #define USH_PIPELINE_MAX_STAGES 8ULL #define USH_PIPE_CAPTURE_MAX USH_COPY_MAX +#define USH_PIPE_TMP_A "/temp/.ush_pipe_a.bin" +#define USH_PIPE_TMP_B "/temp/.ush_pipe_b.bin" #define USH_SORT_MAX_LINES 4096ULL typedef struct ush_pipeline_stage { @@ -2724,16 +2726,89 @@ static int ush_pipeline_parse(const char *line, return 1; } -static int ush_pipeline_write_redirect(const ush_state *sh, const ush_pipeline_stage *stage, const char *data, u64 len) { - char abs_path[USH_PATH_MAX]; - u64 ok; +static int ush_pipeline_open_write_fd(const char *path, u64 flags, u64 *out_fd) { + u64 fd; - if (sh == (const ush_state *)0 || stage == (const ush_pipeline_stage *)0) { + if (path == (const char *)0 || out_fd == (u64 *)0) { + return 0; + } + + fd = cleonos_sys_fd_open(path, flags, 0ULL); + + if (fd == (u64)-1) { + return 0; + } + + *out_fd = fd; + return 1; +} + +static int ush_pipeline_read_path_into_buffer(const char *path, char *buffer, u64 buffer_size, u64 *out_len) { + u64 fd; + u64 total = 0ULL; + int truncated = 0; + char drain[256]; + + if (path == (const char *)0 || buffer == (char *)0 || buffer_size < 2ULL || out_len == (u64 *)0) { + return 0; + } + + *out_len = 0ULL; + buffer[0] = '\0'; + + fd = cleonos_sys_fd_open(path, CLEONOS_O_RDONLY, 0ULL); + + if (fd == (u64)-1) { + return 0; + } + + for (;;) { + u64 got; + u64 room; + + if (total + 1ULL < buffer_size) { + room = (buffer_size - 1ULL) - total; + got = cleonos_sys_fd_read(fd, buffer + total, room); + } else { + got = cleonos_sys_fd_read(fd, drain, (u64)sizeof(drain)); + truncated = 1; + } + + if (got == (u64)-1) { + (void)cleonos_sys_fd_close(fd); + return 0; + } + + if (got == 0ULL) { + break; + } + + if (total + got < buffer_size) { + total += got; + } + } + + (void)cleonos_sys_fd_close(fd); + buffer[total] = '\0'; + *out_len = total; + + if (truncated != 0) { + ush_writeln("[pipe] input truncated"); + } + + return 1; +} + +static int ush_pipeline_open_redirect_fd(const ush_state *sh, const ush_pipeline_stage *stage, u64 *out_fd) { + char abs_path[USH_PATH_MAX]; + u64 flags = CLEONOS_O_WRONLY | CLEONOS_O_CREAT; + + if (sh == (const ush_state *)0 || stage == (const ush_pipeline_stage *)0 || out_fd == (u64 *)0) { return 0; } if (stage->redirect_mode == 0) { - return 1; + return 0; } if (ush_resolve_path(sh, stage->redirect_path, abs_path, (u64)sizeof(abs_path)) == 0) { @@ -2741,14 +2816,19 @@ static int ush_pipeline_write_redirect(const ush_state *sh, const ush_pipeline_s return 0; } - if (stage->redirect_mode == 1) { - ok = cleonos_sys_fs_write(abs_path, data, len); - } else { - ok = cleonos_sys_fs_append(abs_path, data, len); + if (ush_path_is_under_temp(abs_path) == 0) { + ush_writeln("redirect: path must be under /temp"); + return 0; } - if (ok == 0ULL) { - ush_writeln("redirect: write failed"); + if (stage->redirect_mode == 1) { + flags |= CLEONOS_O_TRUNC; + } else { + flags |= CLEONOS_O_APPEND; + } + + if (ush_pipeline_open_write_fd(abs_path, flags, out_fd) == 0) { + ush_writeln("redirect: open failed"); return 0; } @@ -2762,12 +2842,12 @@ static int ush_execute_pipeline(ush_state *sh, ush_pipeline_stage stages[USH_PIPELINE_MAX_STAGES]; u64 stage_count = 0ULL; u64 i; - const char *pipe_in = (const char *)0; - u64 pipe_in_len = 0ULL; - char *capture_out = ush_pipeline_capture_a; - u64 capture_len = 0ULL; + const char *pipe_input_path = (const char *)0; + char *pipe_input_buffer = ush_pipeline_capture_a; + u64 pipe_input_len = 0ULL; int known = 1; int success = 1; + int pipe_output_toggle = 0; if (out_known != (int *)0) { *out_known = 1; @@ -2777,6 +2857,9 @@ static int ush_execute_pipeline(ush_state *sh, *out_success = 0; } + (void)cleonos_sys_fs_remove(USH_PIPE_TMP_A); + (void)cleonos_sys_fs_remove(USH_PIPE_TMP_B); + if (ush_pipeline_parse(line, stages, USH_PIPELINE_MAX_STAGES, &stage_count) == 0) { return 0; } @@ -2784,7 +2867,9 @@ static int ush_execute_pipeline(ush_state *sh, for (i = 0ULL; i < stage_count; i++) { int stage_known = 1; int stage_success = 0; - int mirror_to_tty = ((i + 1ULL) == stage_count && stages[i].redirect_mode == 0) ? 1 : 0; + int use_fd_output = 0; + u64 stage_fd = (u64)-1; + const char *stage_pipe_out = (const char *)0; if (i + 1ULL < stage_count && stages[i].redirect_mode != 0) { ush_writeln("pipe: redirection is only supported on final stage"); @@ -2793,13 +2878,51 @@ static int ush_execute_pipeline(ush_state *sh, break; } - ush_pipeline_set_stdin(pipe_in, pipe_in_len); - ush_output_capture_begin(capture_out, (u64)USH_PIPE_CAPTURE_MAX + 1ULL, mirror_to_tty); - (void)ush_execute_single_command(sh, stages[i].cmd, stages[i].arg, 0, &stage_known, &stage_success); - capture_len = ush_output_capture_end(); + if (pipe_input_path != (const char *)0) { + if (ush_pipeline_read_path_into_buffer(pipe_input_path, + pipe_input_buffer, + (u64)USH_PIPE_CAPTURE_MAX + 1ULL, + &pipe_input_len) == 0) { + ush_writeln("pipe: failed to read stage input"); + success = 0; + break; + } - if (ush_output_capture_truncated() != 0) { - ush_writeln("[pipe] captured output truncated"); + ush_pipeline_set_stdin(pipe_input_buffer, pipe_input_len); + } else { + ush_pipeline_set_stdin((const char *)0, 0ULL); + } + + if (i + 1ULL < stage_count) { + stage_pipe_out = (pipe_output_toggle == 0) ? USH_PIPE_TMP_A : USH_PIPE_TMP_B; + + if (ush_pipeline_open_write_fd(stage_pipe_out, + CLEONOS_O_WRONLY | CLEONOS_O_CREAT | CLEONOS_O_TRUNC, + &stage_fd) == 0) { + ush_writeln("pipe: failed to open temp stream"); + success = 0; + break; + } + + use_fd_output = 1; + } else if (stages[i].redirect_mode != 0) { + if (ush_pipeline_open_redirect_fd(sh, &stages[i], &stage_fd) == 0) { + success = 0; + break; + } + + use_fd_output = 1; + } + + if (use_fd_output != 0) { + ush_output_fd_begin(stage_fd, 0); + } + + (void)ush_execute_single_command(sh, stages[i].cmd, stages[i].arg, 0, &stage_known, &stage_success); + + if (use_fd_output != 0) { + ush_output_fd_end(); + (void)cleonos_sys_fd_close(stage_fd); } if (stage_known == 0) { @@ -2811,19 +2934,17 @@ static int ush_execute_pipeline(ush_state *sh, break; } - if (stages[i].redirect_mode != 0) { - if (ush_pipeline_write_redirect(sh, &stages[i], capture_out, capture_len) == 0) { - success = 0; - break; - } + if (i + 1ULL < stage_count) { + pipe_input_path = stage_pipe_out; + pipe_input_buffer = (pipe_input_buffer == ush_pipeline_capture_a) ? ush_pipeline_capture_b + : ush_pipeline_capture_a; + pipe_output_toggle = (pipe_output_toggle == 0) ? 1 : 0; } - - pipe_in = capture_out; - pipe_in_len = capture_len; - capture_out = (capture_out == ush_pipeline_capture_a) ? ush_pipeline_capture_b : ush_pipeline_capture_a; } ush_pipeline_set_stdin((const char *)0, 0ULL); + (void)cleonos_sys_fs_remove(USH_PIPE_TMP_A); + (void)cleonos_sys_fs_remove(USH_PIPE_TMP_B); if (out_known != (int *)0) { *out_known = known; diff --git a/cleonos/c/apps/shell/shell_internal.h b/cleonos/c/apps/shell/shell_internal.h index b6192ca..1b3ac05 100644 --- a/cleonos/c/apps/shell/shell_internal.h +++ b/cleonos/c/apps/shell/shell_internal.h @@ -88,6 +88,8 @@ void ush_writeln(const char *text); void ush_output_capture_begin(char *buffer, u64 buffer_size, int mirror_to_tty); u64 ush_output_capture_end(void); int ush_output_capture_truncated(void); +void ush_output_fd_begin(u64 fd, int mirror_to_tty); +void ush_output_fd_end(void); void ush_prompt(const ush_state *sh); void ush_write_hex_u64(u64 value); void ush_print_kv_hex(const char *label, u64 value); diff --git a/cleonos/c/apps/shell/shell_util.c b/cleonos/c/apps/shell/shell_util.c index b0d1770..98e424f 100644 --- a/cleonos/c/apps/shell/shell_util.c +++ b/cleonos/c/apps/shell/shell_util.c @@ -225,6 +225,9 @@ static u64 ush_out_capture_length = 0ULL; static int ush_out_capture_active = 0; static int ush_out_capture_mirror_tty = 1; static int ush_out_capture_truncated = 0; +static u64 ush_out_fd = (u64)-1; +static int ush_out_fd_active = 0; +static int ush_out_fd_mirror_tty = 1; static void ush_output_capture_append(const char *text, u64 len) { u64 writable; @@ -295,8 +298,21 @@ int ush_output_capture_truncated(void) { return ush_out_capture_truncated; } +void ush_output_fd_begin(u64 fd, int mirror_to_tty) { + ush_out_fd = fd; + ush_out_fd_active = 1; + ush_out_fd_mirror_tty = (mirror_to_tty != 0) ? 1 : 0; +} + +void ush_output_fd_end(void) { + ush_out_fd = (u64)-1; + ush_out_fd_active = 0; + ush_out_fd_mirror_tty = 1; +} + void ush_write(const char *text) { u64 len; + int should_write_tty = 1; if (text == (const char *)0) { return; @@ -312,23 +328,45 @@ void ush_write(const char *text) { ush_output_capture_append(text, len); if (ush_out_capture_mirror_tty == 0) { - return; + should_write_tty = 0; } } - (void)cleonos_sys_tty_write(text, len); + if (ush_out_fd_active != 0 && ush_out_fd != (u64)-1) { + (void)cleonos_sys_fd_write(ush_out_fd, text, len); + + if (ush_out_fd_mirror_tty == 0) { + should_write_tty = 0; + } + } + + if (should_write_tty != 0) { + (void)cleonos_sys_tty_write(text, len); + } } void ush_write_char(char ch) { + int should_write_tty = 1; + if (ush_out_capture_active != 0) { ush_output_capture_append(&ch, 1ULL); if (ush_out_capture_mirror_tty == 0) { - return; + should_write_tty = 0; } } - (void)cleonos_sys_tty_write_char(ch); + if (ush_out_fd_active != 0 && ush_out_fd != (u64)-1) { + (void)cleonos_sys_fd_write(ush_out_fd, &ch, 1ULL); + + if (ush_out_fd_mirror_tty == 0) { + should_write_tty = 0; + } + } + + if (should_write_tty != 0) { + (void)cleonos_sys_tty_write_char(ch); + } } void ush_writeln(const char *text) {