Fixes#4884
When our command exits, it will close the pty slave fd. This will
trigger a HUP on our poll. Previously, we only checked for IN. When a fd
is closed, IN triggers forever which would leave to an infinite loop and
100% CPU.
Now, detect the HUP and exit the read thread.
Multiple fixes to prevent file descriptor leaks:
- libxev eventfd now uses CLOEXEC
- linux: cgroup clone now uses CLOEXEC for the cgroup fd
- termio pipe uses pipe2 with CLOEXEC
- pty master always sets CLOEXEC because the child doesn't need it
- termio exec now closes pty slave fd after fork
There still appear to be some fd leaks happening. They seem related to
GTK, they aren't things we're accessig directly. I still want to
investigate them but this at least cleans up the major sources of fd
leakage.
## Descriptions
The code was short-circuiting the shell integration setup when
`shell-integration = none`, which prevented the feature environment
variables from being set. These environment variables are needed even
for manual shell integration to work properly.
## Changes
- Extracted feature environment variables setup into a separate
`setup_features` function
- Modified the shell integration initialization to ensure features are
set up even when `shell-integration = none`
<img width="1126" alt="image"
src="https://github.com/user-attachments/assets/ceeb33f5-26ee-4a3b-a6d5-eed57848c96c"
/>
Fixes https://github.com/ghostty-org/ghostty/issues/5046
login(1)'s .hushlogin logic was "fixed" in macOS Sonoma 14.4, so this
comment (and our workaround) is only relevant for versions earlier than
that.
The relevant change to login/login.c is part of system_cmds-979.100.8.
> login.c: look for .hushlogin in home directory (112854361)
- 1bca46ecc5
- https://github.com/apple-oss-distributions/distribution-macOS/tree/macos-144
If the read thread has already exited, it will have closed the read end
of the quit pipe. Unless SIGPIPE is masked with signal(SIGPIPE, SIG_IGN),
or the macOS-specific fcntl(F_SETNOSIGPIPE), writing to the write end of
a broken pipe kills the writer with SIGPIPE instead of returning -EPIPE
as an error. This causes a crash if the read thread exits before
threadExit.
This was already a possible race condition if read() returns
error.NotOpenForReading or error.InputOutput, but it's now much easier to
trigger due to the recent "termio/exec: fix 100% CPU usage after
wait-after-command process exits" fix.
Fix this by closing the quit pipe instead of writing to it.
`std.fs.accessAbsolute` asserts if the user proposed path is absolute,
which we are seemingly passing as-is with no validating that it is.
When running with safety checks on, passing non-absolute path to
--working-directory will make ghostty crash.
I changed it to use `Dir.access`, which is just `accessAbsolute` without
the check.
This has the side effect of also allowing relative working directory.
We're packaging more and more application-specific data directories in
our application bundle. It's helpful to add that path to XDG_DATA_DIRS
so those applications (that support XDG_DATA_DIRS) can locate their data
directories without additional user-level configuration.
This also fixes a typo ("MATHPATH") in the nearby MANPATH-building code.
Fixes#2273
On macOS, killpg is expected to fail with EPERM because of the way we
launch a login process around it. Before this commit, this caused us to
never call waitpid and reap the child process, which caused the child
process to stick around as a zombie.
This commit allows killpg to fail with EPERM on macOS and fall through
to waitpid.
Quoting `man man`:
> If MANPATH begins with a colon, it is appended to the default list;
Alternatively we can think about:
> if it ends with a colon, it is prepended to the default list;
To take preference over existing values, but that shouldn't be really a
problem, as there rather isn't much of another projects named `ghostty`.
Use clone3 / CLONE_INTO_CGROUP to have the Linux kernel create the process in the
correct cgroup rather than move the process into the cgroup after it is created.