aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Copeland <chris@chrisnc.net>2022-07-23 19:51:16 -0700
committerGitHub <noreply@github.com>2022-07-24 02:51:16 +0000
commitc3f3bd36669fc6cf6c5998bfe54cb90ae58dde8f (patch)
tree821c44df359b80a48ed7e59034268bbba58fa5ab
parented4614d0bd2a828a9d89347ad675d4564a3af754 (diff)
downloadalacritty-c3f3bd36669fc6cf6c5998bfe54cb90ae58dde8f.tar.gz
alacritty-c3f3bd36669fc6cf6c5998bfe54cb90ae58dde8f.zip
Register Alacritty shells as tty sessions on macOS
Unless the `shell` config is specified, launch the user's shell with: ```sh login -flp $USER /bin/sh -c "exec -a -shell /path/to/shell" ``` On macOS, just running a shell prefixed by `-` is not sufficient to be registered as a login session for things like `w` and `logname`. However, using the `login` command changes the directory to `$HOME` before running the program by default, which is not desired. The `-l` flag disables this behavior, but also skips prepending `-` to the executed program, so shells will not run as login shells. Instead we just do this part ourselves with `exec -a`. The result is login shells that run in the intended directory and are registered as tty sessions. Fixes #3420.
-rw-r--r--CHANGELOG.md1
-rw-r--r--alacritty.yml3
-rw-r--r--alacritty_terminal/src/tty/unix.rs67
3 files changed, 41 insertions, 30 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4b585df9..08c2db9d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -53,6 +53,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Windows `Open Alacritty Here` on root of drive displaying error
- On macOS, `font.use_thin_strokes` did not work since Big Sur
- On macOS, trying to load a disabled font would crash
+- On macOS, Alacritty sessions did not appear in the list of tty sessions for `w` and `who`
### Removed
diff --git a/alacritty.yml b/alacritty.yml
index d8f05d3f..4301d8e1 100644
--- a/alacritty.yml
+++ b/alacritty.yml
@@ -434,8 +434,7 @@
# shell.
#
# Default:
-# - (macOS) /bin/bash --login
-# - (Linux/BSD) user login shell
+# - (Linux/BSD/macOS) `$SHELL` or the user's login shell, if `$SHELL` is unset
# - (Windows) powershell
#shell:
# program: /bin/bash
diff --git a/alacritty_terminal/src/tty/unix.rs b/alacritty_terminal/src/tty/unix.rs
index 078621df..f52f0920 100644
--- a/alacritty_terminal/src/tty/unix.rs
+++ b/alacritty_terminal/src/tty/unix.rs
@@ -1,8 +1,5 @@
//! TTY related functionality.
-use std::borrow::Cow;
-#[cfg(not(target_os = "macos"))]
-use std::env;
use std::ffi::CStr;
use std::fs::File;
use std::io::{Error, ErrorKind, Result};
@@ -10,7 +7,7 @@ use std::mem::MaybeUninit;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::os::unix::process::CommandExt;
use std::process::{Child, Command, Stdio};
-use std::ptr;
+use std::{env, ptr};
use libc::{self, c_int, winsize, TIOCSCTTY};
use log::error;
@@ -21,7 +18,7 @@ use nix::sys::termios::{self, InputFlags, SetArg};
use signal_hook::consts as sigconsts;
use signal_hook_mio::v0_6::Signals;
-use crate::config::{Program, PtyConfig};
+use crate::config::PtyConfig;
use crate::event::{OnResize, WindowSize};
use crate::tty::{ChildEvent, EventedPty, EventedReadWrite};
@@ -121,17 +118,33 @@ impl Pty {
}
}
-#[cfg(target_os = "macos")]
-fn default_shell(pw: &Passwd<'_>) -> Program {
- let shell_name = pw.shell.rsplit('/').next().unwrap();
- let argv = vec![String::from("-c"), format!("exec -a -{} {}", shell_name, pw.shell)];
-
- Program::WithArgs { program: "/bin/bash".to_owned(), args: argv }
+/// Look for a shell in the `$SHELL` environment variable, then in `passwd`.
+fn default_shell(pw: &Passwd<'_>) -> String {
+ env::var("SHELL").unwrap_or_else(|_| pw.shell.to_owned())
}
#[cfg(not(target_os = "macos"))]
-fn default_shell(pw: &Passwd<'_>) -> Program {
- Program::Just(env::var("SHELL").unwrap_or_else(|_| pw.shell.to_owned()))
+fn default_shell_command(pw: &Passwd<'_>) -> Command {
+ Command::new(default_shell(pw))
+}
+
+#[cfg(target_os = "macos")]
+fn default_shell_command(pw: &Passwd<'_>) -> Command {
+ let shell = default_shell(pw);
+ let shell_name = shell.rsplit('/').next().unwrap();
+
+ // On macOS, use the `login` command so the shell will appear as a tty session.
+ let mut login_command = Command::new("/usr/bin/login");
+
+ // Exec the shell with argv[0] prepended by '-' so it becomes a login shell.
+ // `login` normally does this itself, but `-l` disables this.
+ let exec = format!("exec -a -{} {}", shell_name, shell);
+
+ // -f: Bypasses authentication for the already-logged-in user.
+ // -l: Skips changing directory to $HOME and prepending '-' to argv[0].
+ // -p: Preserves the environment.
+ login_command.args(["-flp", pw.name, "/bin/sh", "-c", &exec]);
+ login_command
}
/// Create a new TTY and return a handle to interact with it.
@@ -148,16 +161,14 @@ pub fn new(config: &PtyConfig, window_size: WindowSize, window_id: Option<usize>
let mut buf = [0; 1024];
let pw = get_pw_entry(&mut buf)?;
- let shell = match config.shell.as_ref() {
- Some(shell) => Cow::Borrowed(shell),
- None => Cow::Owned(default_shell(&pw)),
+ let mut builder = if let Some(shell) = config.shell.as_ref() {
+ let mut cmd = Command::new(shell.program());
+ cmd.args(shell.args());
+ cmd
+ } else {
+ default_shell_command(&pw)
};
- let mut builder = Command::new(shell.program());
- for arg in shell.args() {
- builder.arg(arg);
- }
-
// Setup child stdin/stdout/stderr as slave fd of PTY.
// Ownership of fd is transferred to the Stdio structs and will be closed by them at the end of
// this scope. (It is not an issue that the fd is closed three times since File::drop ignores
@@ -171,10 +182,6 @@ pub fn new(config: &PtyConfig, window_size: WindowSize, window_id: Option<usize>
builder.env("USER", pw.name);
builder.env("HOME", pw.dir);
- // Set $SHELL environment variable on macOS, since login does not do it for us.
- #[cfg(target_os = "macos")]
- builder.env("SHELL", config.shell.as_ref().map_or(pw.shell, Program::program));
-
if let Some(window_id) = window_id {
builder.env("WINDOWID", format!("{}", window_id));
}
@@ -210,7 +217,7 @@ pub fn new(config: &PtyConfig, window_size: WindowSize, window_id: Option<usize>
}
// Prepare signal handling before spawning child.
- let signals = Signals::new(&[sigconsts::SIGCHLD]).expect("error preparing signal handling");
+ let signals = Signals::new([sigconsts::SIGCHLD]).expect("error preparing signal handling");
match builder.spawn() {
Ok(child) => {
@@ -231,8 +238,12 @@ pub fn new(config: &PtyConfig, window_size: WindowSize, window_id: Option<usize>
Ok(pty)
},
Err(err) => Err(Error::new(
- ErrorKind::NotFound,
- format!("Failed to spawn command '{}': {}", shell.program(), err),
+ err.kind(),
+ format!(
+ "Failed to spawn command '{}': {}",
+ builder.get_program().to_string_lossy(),
+ err
+ ),
)),
}
}