From 5e3e76bcae7350de1c25a3fe85666e7c4f02f820 Mon Sep 17 00:00:00 2001 From: Matthew Winter <33818+wintermi@users.noreply.github.com> Date: Sat, 30 Dec 2023 03:51:16 +1100 Subject: [PATCH 1/4] Modify the way the login shell is launched on macOS to reduce nesting --- src/termio/Exec.zig | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/termio/Exec.zig b/src/termio/Exec.zig index 50fcf3c7f..6b1357043 100644 --- a/src/termio/Exec.zig +++ b/src/termio/Exec.zig @@ -841,12 +841,6 @@ const Subprocess = struct { break :hush if (dir.access(".hushlogin", .{})) true else |_| false; } else false; - const cmd = try std.fmt.allocPrint( - alloc, - "exec -l {s}", - .{opts.full_config.command orelse default_path}, - ); - // The reason for executing login this way is unclear. This // comment will attempt to explain but prepare for a truly // unhinged reality. @@ -892,15 +886,11 @@ const Subprocess = struct { try args.append("-flp"); try args.append(username); - // We execute zsh with "-d -f" so that it doesn't load any - // local zshrc files so that (1) our shell integration doesn't - // break and (2) user configuration doesn't mess this process - // up. - try args.append("/bin/zsh"); - try args.append("-d"); - try args.append("-f"); - try args.append("-c"); - try args.append(cmd); + // We execute `env` to run the command (aka shell) in a + // modified environment and not use another shell interpreter + // to launch the shell environment. + try args.append("/usr/bin/env"); + try args.append(opts.full_config.command orelse default_path); break :args try args.toOwnedSlice(); } From 9989436beb18ab9ae5c44fe9187f81bb7afc59fc Mon Sep 17 00:00:00 2001 From: Matthew Winter <33818+wintermi@users.noreply.github.com> Date: Sat, 30 Dec 2023 04:32:13 +1100 Subject: [PATCH 2/4] Ensure the shell environment passes the Login Shell test --- src/termio/Exec.zig | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/termio/Exec.zig b/src/termio/Exec.zig index 6b1357043..7912875e5 100644 --- a/src/termio/Exec.zig +++ b/src/termio/Exec.zig @@ -883,13 +883,8 @@ const Subprocess = struct { // Awesome. try args.append("/usr/bin/login"); if (hush) try args.append("-q"); - try args.append("-flp"); + try args.append("-fp"); try args.append(username); - - // We execute `env` to run the command (aka shell) in a - // modified environment and not use another shell interpreter - // to launch the shell environment. - try args.append("/usr/bin/env"); try args.append(opts.full_config.command orelse default_path); break :args try args.toOwnedSlice(); } From 992888d4bdc148339086557dc3636c605b4a276b Mon Sep 17 00:00:00 2001 From: Matthew Winter <33818+wintermi@users.noreply.github.com> Date: Sat, 30 Dec 2023 05:40:07 +1100 Subject: [PATCH 3/4] Ensure the cwd is not changed, whilst remaining a logon shell --- src/termio/Exec.zig | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/termio/Exec.zig b/src/termio/Exec.zig index 7912875e5..2624c6e52 100644 --- a/src/termio/Exec.zig +++ b/src/termio/Exec.zig @@ -841,6 +841,12 @@ const Subprocess = struct { break :hush if (dir.access(".hushlogin", .{})) true else |_| false; } else false; + const cmd = try std.fmt.allocPrint( + alloc, + "exec -l {s}", + .{opts.full_config.command orelse default_path}, + ); + // The reason for executing login this way is unclear. This // comment will attempt to explain but prepare for a truly // unhinged reality. @@ -883,9 +889,11 @@ const Subprocess = struct { // Awesome. try args.append("/usr/bin/login"); if (hush) try args.append("-q"); - try args.append("-fp"); + try args.append("-flp"); try args.append(username); - try args.append(opts.full_config.command orelse default_path); + try args.append("/bin/sh"); + try args.append("-c"); + try args.append(cmd); break :args try args.toOwnedSlice(); } From a69ec2127ed877c8607aef353a5591b6d05dfcfb Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 29 Dec 2023 15:41:11 -0800 Subject: [PATCH 4/4] termio/exec: use bash instead of zsh for shell launching --- src/termio/Exec.zig | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/termio/Exec.zig b/src/termio/Exec.zig index 2624c6e52..8e8449559 100644 --- a/src/termio/Exec.zig +++ b/src/termio/Exec.zig @@ -878,10 +878,15 @@ const Subprocess = struct { // "-q" flag to login(1). // // So to get all the behaviors we want, we specify "-l" but - // execute "zsh" (which is built-in to macOS). We then use - // the zsh builtin "exec" to replace the process with a login + // execute "bash" (which is built-in to macOS). We then use + // the bash builtin "exec" to replace the process with a login // shell ("-l" on exec) with the command we really want. // + // We use "bash" instead of other shells that ship with macOS + // because as of macOS Sonoma, we found with a microbenchmark + // that bash can `exec` into the desired command ~2x faster + // than zsh. + // // To figure out a lot of this logic I read the login.c // source code in the OSS distribution Apple provides for // macOS. @@ -890,8 +895,15 @@ const Subprocess = struct { try args.append("/usr/bin/login"); if (hush) try args.append("-q"); try args.append("-flp"); + + // We execute bash with "--noprofile --norc" so that it doesn't + // load startup files so that (1) our shell integration doesn't + // break and (2) user configuration doesn't mess this process + // up. try args.append(username); - try args.append("/bin/sh"); + try args.append("/bin/bash"); + try args.append("--noprofile"); + try args.append("--norc"); try args.append("-c"); try args.append(cmd); break :args try args.toOwnedSlice();