summaryrefslogtreecommitdiffstats
path: root/src/shell.h
diff options
context:
space:
mode:
authorEthan Werner <mail@ethanwerner.com>2026-10-10 20:55:33 +0000
committerEthan Werner <mail@ethanwerner.com>2026-10-10 20:56:50 +0000
commitf8423ebea413605b42de23f5dd06c5479d3fa1dd (patch)
tree2612a5eb026c59e7aae01f10a1cf62f2ee43042c /src/shell.h
initial commitHEADmaster
Diffstat (limited to 'src/shell.h')
-rw-r--r--src/shell.h49
1 files changed, 49 insertions, 0 deletions
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 <pthread.h>
+#include <stdbool.h>
+
+/* 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/<pid>/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