feat: ports - git port
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
# git for MontaukOS
|
||||
|
||||
Upstream [git/git](https://github.com/git/git), pinned at **v2.39.5**
|
||||
(`upstream/`, submodule). Reports itself as `2.39.5-montauk`.
|
||||
|
||||
Installs as a system program, not an app bundle:
|
||||
|
||||
| Path | What |
|
||||
|------|------|
|
||||
| `0:/os/git.elf` | the binary (~3 MB stripped) |
|
||||
| `0:/os/git/share/git-core/templates` | `git init` skeleton |
|
||||
| `0:/os/git/etc/gitconfig` | system config (not created by the install) |
|
||||
|
||||
```bash
|
||||
make -C dev-vcs/git # build
|
||||
make -C dev-vcs/git install # -> MontaukOS/programs/bin/os/
|
||||
```
|
||||
|
||||
`make ports` from the MontaukOS tree does both (git is in the top-level
|
||||
Makefile's `SELF_INSTALL_PORTS`).
|
||||
|
||||
## Status
|
||||
|
||||
First run on hardware: `git` started, died at exit 128, printed nothing. Two
|
||||
bugs, both outside git and both now fixed -- **needs a retest**:
|
||||
|
||||
1. **`sanitize_stdfds()` opened `/dev/null`**, which MontaukOS does not have,
|
||||
so `xopen()` died before any command dispatched. That function guards
|
||||
against inheriting closed descriptors, which cannot happen on a system that
|
||||
spawns rather than forks; `patches/0002` makes it a no-op.
|
||||
2. **Nothing git wrote with `write(2, ...)` ever appeared** -- which is why
|
||||
the fatal error was invisible. The libc's `read()`/`write()` passed fd 0/1/2
|
||||
straight to `SYS_READ`/`SYS_FWRITE` as file handles, and the kernel hands
|
||||
out file handles starting at 0, so those numbers named real files. A
|
||||
program's third `open()` owned "stderr". Fixed in the OS: the kernel no
|
||||
longer allocates handles 0/1/2, and the libc routes them to the terminal.
|
||||
|
||||
Second run got as far as `git init` (works, repository created) and then hit
|
||||
`fatal: detected dubious ownership`. That is git's safe.directory check
|
||||
comparing `lstat()`'s `st_uid` against `geteuid()`; MontaukOS stores no
|
||||
per-file owner, so it is false for every directory on the system. The port now
|
||||
answers that check directly -- see `compat/montauk-ownership.h`, which also
|
||||
records what has to change when the OS grows real ownership.
|
||||
|
||||
Confirmed working on hardware so far: startup, error output, `git init`, and
|
||||
quoted arguments. The rest is still only what the build configuration
|
||||
implies.
|
||||
|
||||
## What should work
|
||||
|
||||
Everything git does inside one process and one filesystem:
|
||||
|
||||
- `init`, `add`, `rm`, `mv`, `status`, `diff`, `commit`, `log`, `show`
|
||||
- `branch`, `checkout`, `switch`, `restore`, `merge`, `reset`, `revert`
|
||||
- `tag`, `stash`, `cherry-pick`, `rebase` (the builtin, non-interactive path)
|
||||
- `cat-file`, `rev-parse`, `ls-files`, `ls-tree`, `hash-object`, `fsck`
|
||||
- `config`, `blame`, `grep`, `describe`, `bisect`
|
||||
- `clone`/`fetch`/`push` **against a local path**, e.g.
|
||||
`git clone 0:/users/dan/repo`
|
||||
|
||||
## What does not work, and why
|
||||
|
||||
**Anything that starts another process.** MontaukOS spawns (`SYS_SPAWN`); it
|
||||
has no `fork()`, no `exec()` and no `pipe()`, and a spawned process cannot
|
||||
inherit a pipe for its stdio. Every git feature built on sub-processes fails
|
||||
with `ENOSYS` rather than misbehaving:
|
||||
|
||||
- hooks (`pre-commit`, `commit-msg`, ...) -- the samples are installed but
|
||||
never run
|
||||
- `$EDITOR`, so `git commit` needs `-m` or `-F`, and interactive rebase and
|
||||
`git add -p` are out
|
||||
- the pager (harmless -- output goes straight to the terminal, and
|
||||
`DEFAULT_PAGER=cat` is compiled in anyway)
|
||||
- aliases that shell out (`!command`), `git submodule`, `difftool`,
|
||||
`mergetool`, `git gc` (it re-runs itself as `git repack`)
|
||||
|
||||
**Network transports.** No `http://`, `https://`, `git://` or `ssh://`. The
|
||||
port is built `NO_CURL NO_OPENSSL`, and the socket shims fail: MontaukOS TCP
|
||||
lives behind IPC handles rather than file descriptors, and DNS resolution is
|
||||
inside the kernel with no userspace interface. Local paths are the transport.
|
||||
|
||||
**Symlinks.** The VFS cannot create them, so git behaves as if
|
||||
`core.symlinks=false` -- a symlink in a tree checks out as a regular file
|
||||
containing the link target.
|
||||
|
||||
**File modes.** Built `NO_TRUSTABLE_FILEMODE`, so the executable bit is not
|
||||
read back from the filesystem; `core.fileMode` defaults to false.
|
||||
|
||||
**Threads.** `NO_PTHREADS`, so packing, delta search and `git grep` are
|
||||
single-threaded. Correct, just slower.
|
||||
|
||||
**`mmap`.** `NO_MMAP`, so pack and index access reads into memory instead of
|
||||
mapping. Large repositories will be heavier on RAM than on Linux.
|
||||
|
||||
## Before the first commit
|
||||
|
||||
The environment MontaukOS hands a process is empty, so the port sets `HOME`
|
||||
itself from the session user (`0:/users/<name>`) before git reads any config
|
||||
-- that is what makes `--global` work. Set an identity:
|
||||
|
||||
```
|
||||
git config --global user.name "Your Name"
|
||||
git config --global user.email [email protected]
|
||||
```
|
||||
|
||||
This is not optional. Left unset, git builds a fallback address from the
|
||||
session user and the hostname -- and since `gethostname()` answers `montauk`,
|
||||
with no domain in it, git marks the address bogus, appends `.(none)` and
|
||||
refuses:
|
||||
|
||||
```
|
||||
fatal: unable to auto-detect email address (got 'admin@montauk.(none)')
|
||||
```
|
||||
|
||||
That is stock git behaviour on any host without a domain name, not something
|
||||
the port introduces.
|
||||
|
||||
## Quoting
|
||||
|
||||
Arguments are split by the C runtime, not by a shell. `crt1.c` understands
|
||||
`'...'` and `"..."` (added for this port), so
|
||||
|
||||
```
|
||||
git commit -m "a message with spaces"
|
||||
```
|
||||
|
||||
reaches git as three arguments. There is no escaping and no substitution --
|
||||
a literal quote character cannot be passed.
|
||||
|
||||
## How the port is put together
|
||||
|
||||
`Makefile` drives upstream's own build with the toolchain and a long list of
|
||||
`NO_*` knobs; the header comment there explains the ones that are not
|
||||
self-evident. Two mechanisms fill the gaps:
|
||||
|
||||
- `compat/` -- headers MontaukOS has no equivalent of, plus
|
||||
`libgitcompat.a` with the POSIX functions the libc does not carry. See
|
||||
`compat/README`.
|
||||
- `patches/` -- two patches: calling `montauk_startup()` from `main()`, and
|
||||
emptying `sanitize_stdfds()`, which cannot run without a `/dev/null`.
|
||||
|
||||
Everything else upstream needed was already reachable through git's own
|
||||
portability knobs, which is the reason this port is small.
|
||||
Reference in New Issue
Block a user