Kitty: Shells not running in interactive mode on some macOS systems

Created on 22 Dec 2017  路  22Comments  路  Source: kovidgoyal/kitty

It seems currently it's not possible to set a login shell in kitty. This breaks my $PATH and possibly some other profile settings, so I have to manually run "login" before using the shell.

Here's a similar issue in Alacritty and the solution:
https://github.com/jwilm/alacritty/issues/645

help wanted macOS

Most helpful comment

I just installed kitty 0.7.1 with brew cask and having shell /bin/zsh --login in my kitty.conf works.

All 22 comments

You can specify whatever program you want to run in kitty directly on the command line. Like this

/Applications/kitty.app/Contents/MacOS/kitty bash --login

However, that is not an actual fix for this issue. The problem is why is your bash (or whatever shell you use) not starting an interactive shell session. Someone who can reproduce the issue will need to figure that out. I cannot reproduce it. I suspect it is some assumption somewhere in some shell initialization scripts in either your user account or system-wide that fails for kitty.

I noticed that commit 6ad49bd7fb6eb6426d7d5f028da71140d88e6655 made 12 days ago introduced a configuration option to specify the default shell. This should make it easy to configure in kitty.conf, for example:

shell /bin/zsh --login

I think this is a valid discussion, regarding how to best handle default shell integration in a way that is both flexible and works well across different systems.

I'm familiar with how iTerm2, a mature terminal emulator which is extremely popular on macOS, has a configuration option for either choosing a login shell, which is automatically determined by checking the $SHELL environment variable, or a user-provided default command:

iterm-default-command-configuration

I think it could be valuable to understand how the popular terminal emulators handle this tricky setting and the advantages and disadvantages experienced across a wide range of usage scenarios.

Weird, iTerm uses SHELL? Strange choice. The correct, non shell dependent way to read the login shell is from the /etc/passwd database, which is what kitty already does.

@kovidgoyal macOS isn't using /etc/passwd, at least not for "regular" users.

On the contrary, the Unix passwd database is available on all unix systems, including macOS. Try this on your mac:

python -c "import pwd, os; print(pwd.getpwuid(os.geteuid()).pw_shell)"

The actual database may not be stored in /etc/passwd on macOS, but the API's for querying it are the same.

And see man getpwuid for details.

GNU Screen appears to check the $SHELL environment variable also. Maybe there's something to it.

The passwd database is the canonical place to check for the login shell. Checking $SHELL is just wrong, regardless of how many programs might be doing it. To understand why, just look at chsh. If you use SHELL to detect the users login SHELL then using chsh alone is not enough to change your login shell, you have to reboot as well (well technically log out and login again), so that whatever component on your system is setting the SHELL env var can update it based on the passwd database..

Nice

I just installed kitty 0.7.1 with brew cask and having shell /bin/zsh --login in my kitty.conf works.

'shell' option helped me as well

There's some background info in the iTerm2 source: https://github.com/gnachman/iTerm2/blob/f6b54d66b5e371b9e69a0881e9608e13e710fda1/sources/shell_launcher.c#L1

It's been a while since I've written any C, and this is really a dirty hack, but it seems to work for me.

From d0733d50cf4379dead247030e1901810377f0bb4 Mon Sep 17 00:00:00 2001
From: Kaleb Elwert <[email protected]>
Date: Sun, 4 Mar 2018 21:53:25 -0800
Subject: [PATCH] Dirty hack to run the shell as a login shell

---
 kitty/child.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/kitty/child.c b/kitty/child.c
index 3fb3f88..1793f4e 100644
--- a/kitty/child.c
+++ b/kitty/child.c
@@ -49,6 +49,13 @@ spawn(PyObject *self UNUSED, PyObject *args) {
     char **argv = serialize_string_tuple(argv_p);
     char **env = serialize_string_tuple(env_p);

+    char *argv0 = argv[0];
+    argv[0] = calloc(strlen(argv[0]) + 2, sizeof(char));
+    argv[0][0] = '-';
+    for (unsigned long i = 0; i < strlen(argv0); i++) {
+        argv[0][i+1] = argv0[i];
+    }
+
 #define exit_on_err(m) { write_to_stderr(m); write_to_stderr(": "); write_to_stderr(strerror(errno)); exit(EXIT_FAILURE); }
     pid_t pid = fork();
     switch(pid) {
@@ -76,7 +83,7 @@ spawn(PyObject *self UNUSED, PyObject *args) {
             close(tfd);

             environ = env;
-            execvp(argv[0], argv);
+            execvp(argv0, argv);
             // Report the failure and exec a shell instead, so that we are not left
             // with a forked but not exec'ed process
             write_to_stderr("Failed to launch child: ");
--
2.14.3 (Apple Git-98)

EDIT: Slightly cleaner patch using asprintf.

From e7faf0c1e510e90feaaeff23f81c8f160b75e50c Mon Sep 17 00:00:00 2001
From: Kaleb Elwert <[email protected]>
Date: Sun, 4 Mar 2018 21:53:25 -0800
Subject: [PATCH] Dirty hack to run the shell as a login shell

---
 kitty/child.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/kitty/child.c b/kitty/child.c
index 3fb3f88..c9a1a35 100644
--- a/kitty/child.c
+++ b/kitty/child.c
@@ -5,6 +5,8 @@
  * Distributed under terms of the GPL3 license.
  */

+#define _DARWIN_C_SOURCE 1
+
 #include "data-types.h"
 #include <unistd.h>
 #include <sys/stat.h>
@@ -50,6 +52,10 @@ spawn(PyObject *self UNUSED, PyObject *args) {
     char **env = serialize_string_tuple(env_p);

 #define exit_on_err(m) { write_to_stderr(m); write_to_stderr(": "); write_to_stderr(strerror(errno)); exit(EXIT_FAILURE); }
+
+    char *argv0 = argv[0];
+    if (asprintf(&argv[0], "-%s", argv0) == -1) exit_on_err("asprintf() failed to allocate memory");
+
     pid_t pid = fork();
     switch(pid) {
         case 0:
@@ -76,7 +82,7 @@ spawn(PyObject *self UNUSED, PyObject *args) {
             close(tfd);

             environ = env;
-            execvp(argv[0], argv);
+            execvp(argv0, argv);
             // Report the failure and exec a shell instead, so that we are not left
             // with a forked but not exec'ed process
             write_to_stderr("Failed to launch child: ");
--
2.14.3 (Apple Git-98)

Interesting, here's some more info on using a leading - https://unix.stackexchange.com/questions/128936/why-we-can-not-see-a-single-hyphen-from-0-on-a-login-shell-invoked-with-logi

My concern is that the command kitty runs is arbitrary, it need not be a shell at all. For instance, I usually run vim and mutt in kitty directly with no intervening shell. I'm not sure what effect adding - to argv[0] would have in those cases. Maybe only do it on macOS and only if argv[0] endswith sh

What about only doing it if the command isn't specified? If you're specifying the command manually and you're running a shell, you can add --login yourself. This will improve the default case and shouldn't break anything.

Awesome! The fix works for me. I was spending a bit of time trying to figure out how to get the info needed out of the python layer - glad it was a simple change. Thanks. :)

You're welcome and thanks for finding the root cause :)

I'm not exactly sure what the problem _is_, but this seems to still be occurring on osx mojave, running latest / 0.13.2

so set your shell to

bash --login

assuming you are using bash or the equivalent for whatever shell you are using.

I'm not sure if the root cause is the same, C02WC2EQHTDD:~ mphillips81$ shopt | grep log login_shell on is set, but it seems kitty launched from finder/directly ignores $HOME/.config/kitty/kitty.conf. when I launch it from Terminal/iterm etc, it seems fine. I'm not exactly sure how to get stdout/debug logging for kitty since the debug output is only turned on from argv parameters?

debug output when launched via launch services will be in console.app.
And when you launch from inside a shell, the value OF PATH and HOME and
other env vars will be different from what it is when launched via
launch services.

ah, false alarm @kovidgoyal, there were existing kitty processes running in the background (realized this when open -a kitty --new did the right thing). once I killed those the new fresh config was picked up, so things are working as expected. thanks 馃憤

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mihaicristiantanase picture mihaicristiantanase  路  3Comments

jasminabasurita picture jasminabasurita  路  3Comments

Ulrar picture Ulrar  路  3Comments

keyofnight picture keyofnight  路  3Comments

hujianxin picture hujianxin  路  3Comments