1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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
|