From f8423ebea413605b42de23f5dd06c5479d3fa1dd Mon Sep 17 00:00:00 2001 From: Ethan Werner Date: Sat, 10 Oct 2026 20:55:33 +0000 Subject: initial commit --- src/shell.h | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/shell.h (limited to 'src/shell.h') diff --git a/src/shell.h b/src/shell.h new file mode 100644 index 0000000..18c8f67 --- /dev/null +++ b/src/shell.h @@ -0,0 +1,49 @@ +#ifndef LLSH_SHELL_H +#define LLSH_SHELL_H + +#include "util.h" +#include +#include + +/* An interactive user shell running on a private PTY. llsh forwards raw + * terminal input to the PTY and streams the PTY's output back to the real + * terminal, so the shell's own line editor (Tab completion, history, …) is + * used while in shell mode. Mirrors the Rust `InteractiveShell` in main.rs. + * POSIX-only (forkpty/raw mode). */ +typedef struct interactive_shell { + int pid; /* shell PID; 0 once reaped */ + int master; /* PTY master fd; -1 once closed */ + int reader_fd; /* dup of master, owned by the reader thread */ + pthread_t reader_th; + pthread_mutex_t done_mu; /* guards reader_done */ + bool reader_done; /* set by the reader thread on EOF */ + xbuf outbuf; /* owned; output capture (shared with reader thread) */ + pthread_mutex_t out_mu; /* guards outbuf */ + unsigned long capture_cap; /* max bytes to capture (bounds memory) */ + char *last_cwd; /* owned; last observed cwd (fallback after reap) */ +} interactive_shell; + +/* Fork `$SHELL` (else `bash`) with `-i` on a private PTY and start a reader + * thread that streams the shell's output to stdout (CRLF collapsed to LF). + * Returns NULL on failure. */ +interactive_shell *shell_spawn(void); +/* Forward raw input bytes to the shell. 0 on success, -1 on error. */ +int shell_write(const interactive_shell *s, const void *buf, size_t len); +/* Resize the PTY to match the current terminal size. */ +void shell_update_winsize(const interactive_shell *s); +/* True once the shell has exited, its output is drained, and it has been + * reaped. Cheap to call each loop iteration while in shell mode. */ +bool shell_reap_if_dead(interactive_shell *s); +/* The directory the shell ended in: a live `/proc//cwd` read while it + * is still alive, falling back to the last observed directory once reaped. + * Returns a freshly allocated string, or NULL when unknown. */ +char *shell_final_cwd(const interactive_shell *s); +/* Everything the shell has printed so far (owned copy), and reset the + * capture. Thread-safe against the reader thread; returns an empty string + * when nothing was captured. */ +char *shell_captured(interactive_shell *s); +/* Kill the shell (whole process group), close the PTY, and join the reader + * thread. Safe to call on a fully-reaped shell. */ +void shell_free(interactive_shell *s); + +#endif -- cgit v1.3.1