Add builtin dispatch in lcmd.c that checks __builtins table before fork(), so cd/exec/umask operate on the shell process itself.
55 lines
2.5 KiB
Markdown
55 lines
2.5 KiB
Markdown
# 15 — Shell builtins
|
|
|
|
**Status:** done
|
|
|
|
Some commands must run inside the shell process itself to have any effect. An external `cd` binary exists on most systems but it spawns a subprocess, changes directory there, and exits — leaving lush's own working directory unchanged.
|
|
|
|
Lush only needs builtins for operations that **cannot be implemented in pure Lua or via external binaries** — things that require modifying the shell process state via syscalls with no Lua API.
|
|
|
|
## Assessment
|
|
|
|
Every builtin from `man 1 builtin` was evaluated against two questions:
|
|
1. Can it be done in Lua? (e.g. `export` → `$VAR = "val"`, `source` → `dofile()`, `exit` → `os.exit()`)
|
|
2. Does the external binary work? (e.g. `/bin/pwd`, `/usr/bin/which`, `/usr/bin/kill`)
|
|
|
|
If either answer is yes, it's not needed as a builtin. What remains:
|
|
|
|
| Builtin | Why it must be a builtin |
|
|
|---------|-------------------------|
|
|
| **`cd`** | `chdir(2)` must happen in the lush process. No Lua API. |
|
|
| **`exec`** | `execvp(2)` replaces the current process. `os.execute()` spawns a subprocess. No Lua equivalent. |
|
|
| **`umask`** | `umask(2)` is per-process. The external `/usr/bin/umask` is a shell script that calls the shell's own builtin. No Lua API. |
|
|
|
|
## Builtins
|
|
|
|
### `cd [dir]`
|
|
|
|
Change working directory via `chdir(2)`.
|
|
|
|
- No argument: `cd $HOME`
|
|
- `cd -`: change to `$OLDPWD`
|
|
- Updates `$PWD` and `$OLDPWD` environment variables
|
|
- Errors if directory doesn't exist or isn't accessible
|
|
|
|
### `exec command [args...]`
|
|
|
|
Replace the shell process with the given command via `execvp(2)`. Does not return on success. On failure, prints an error and the shell continues.
|
|
|
|
### `umask [mode]`
|
|
|
|
Get or set the file creation mask via `umask(2)`.
|
|
|
|
- No argument: print current umask (octal)
|
|
- With argument: set umask to the given octal value
|
|
|
|
## Design considerations
|
|
|
|
- **Dispatch order:** When a command is entered (backtick or `!` prefix), check builtins *before* searching `$PATH`. A builtin named `cd` must intercept the command before it reaches `execvp`.
|
|
- **Implementation:** Expose the syscalls to Lua (e.g. `os.chdir()`, `os.exec()`, `os.umask()`), then implement the builtins as Lua functions registered at startup. This keeps the C side minimal and lets users compose with the primitives directly.
|
|
- **Interaction with backticks:** `` `cd /tmp` `` and `!cd /tmp` should both trigger the builtin, not spawn an external process.
|
|
|
|
## Open questions
|
|
|
|
- Should builtins be overridable by the user?
|
|
- Should there be a `builtin` command to bypass user overrides?
|