From 76a4c373da48a4477c07b844442e5599fbd37ada Mon Sep 17 00:00:00 2001 From: Mattbazooka Date: Tue, 14 Jul 2020 19:03:36 +1000 Subject: [PATCH] Fallback to SHELL instead of passwd if present Instead of just always falling back to the shell specified in the passwd file when no config or cli shell was specified, Alacritty will not first look at the `$SHELL` environment variable. If this is unset, it will still read the passwd file. Since macOS is a bit peculiar and does not set the `$SHELL` environment variable by default, it is set manually to the shell used by Alacritty while any existing `$SHELL` variables are ignored. This matches the behavior of iTerm and Terminal.app. Co-authored-by: Christian Duerr --- CHANGELOG.md | 1 + alacritty_terminal/src/tty/unix.rs | 66 ++++++++++++++++++------------ 2 files changed, 40 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1cea655..e773d4e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Support for `gopher` and `gemini` URLs - Unicode 13 support - Option to run command on bell which can be set in `bell.command` +- Fallback to program specified in `$SHELL` variable on Linux/BSD if it is present ### Changed diff --git a/alacritty_terminal/src/tty/unix.rs b/alacritty_terminal/src/tty/unix.rs index b6807cc2..b373ada2 100644 --- a/alacritty_terminal/src/tty/unix.rs +++ b/alacritty_terminal/src/tty/unix.rs @@ -1,18 +1,7 @@ //! TTY related functionality. -use crate::config::{Config, Program}; -use crate::event::OnResize; -use crate::term::SizeInfo; -use crate::tty::{ChildEvent, EventedPty, EventedReadWrite}; - -use libc::{self, c_int, pid_t, winsize, TIOCSCTTY}; -use log::error; -use nix::pty::openpty; -#[cfg(any(target_os = "linux", target_os = "macos"))] -use nix::sys::termios::{self, InputFlags, SetArg}; -use signal_hook::{self as sighook, iterator::Signals}; - -use mio::unix::EventedFd; +use std::borrow::Cow; +use std::env; use std::ffi::CStr; use std::fs::File; use std::io; @@ -25,6 +14,19 @@ use std::process::{Child, Command, Stdio}; use std::ptr; use std::sync::atomic::{AtomicUsize, Ordering}; +use libc::{self, c_int, pid_t, winsize, TIOCSCTTY}; +use log::error; +use mio::unix::EventedFd; +use nix::pty::openpty; +#[cfg(any(target_os = "linux", target_os = "macos"))] +use nix::sys::termios::{self, InputFlags, SetArg}; +use signal_hook::{self as sighook, iterator::Signals}; + +use crate::config::{Config, Program}; +use crate::event::OnResize; +use crate::term::SizeInfo; +use crate::tty::{ChildEvent, EventedPty, EventedReadWrite}; + /// Process ID of child process. /// /// Necessary to put this in static storage for `SIGCHLD` to have access. @@ -128,13 +130,22 @@ pub struct Pty { signals_token: mio::Token, } +#[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 } +} + +#[cfg(not(target_os = "macos"))] +fn default_shell(pw: &Passwd<'_>) -> Program { + Program::Just(env::var("SHELL").unwrap_or_else(|_| pw.shell.to_owned())) +} + /// Create a new TTY and return a handle to interact with it. pub fn new(config: &Config, size: &SizeInfo, window_id: Option) -> Pty { - let win_size = size.to_winsize(); - let mut buf = [0; 1024]; - let pw = get_pw_entry(&mut buf); - - let (master, slave) = make_pty(win_size); + let (master, slave) = make_pty(size.to_winsize()); #[cfg(any(target_os = "linux", target_os = "macos"))] { @@ -145,17 +156,15 @@ pub fn new(config: &Config, size: &SizeInfo, window_id: Option) -> } } - let default_shell = if cfg!(target_os = "macos") { - let shell_name = pw.shell.rsplit('/').next().unwrap(); - let argv = vec![String::from("-c"), format!("exec -a -{} {}", shell_name, pw.shell)]; + let mut buf = [0; 1024]; + let pw = get_pw_entry(&mut buf); - Program::WithArgs { program: "/bin/bash".to_owned(), args: argv } - } else { - Program::Just(pw.shell.to_owned()) + let shell = match config.shell.as_ref() { + Some(shell) => Cow::Borrowed(shell), + None => Cow::Owned(default_shell(&pw)), }; - let shell = config.shell.as_ref().unwrap_or(&default_shell); - let mut builder = Command::new(&*shell.program()); + let mut builder = Command::new(shell.program()); for arg in shell.args() { builder.arg(arg); } @@ -171,9 +180,12 @@ pub fn new(config: &Config, size: &SizeInfo, window_id: Option) -> // Setup shell environment. builder.env("LOGNAME", pw.name); builder.env("USER", pw.name); - builder.env("SHELL", pw.shell); 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(|sh| sh.program()).unwrap_or(pw.shell)); + if let Some(window_id) = window_id { builder.env("WINDOWID", format!("{}", window_id)); }